package facecat

import (
	"fmt"
    "math"
    "syscall"
	"unsafe"
    "bytes"
    "strconv"
    "strings"
    "time"
    "sort"
    "crypto/rand"
    "encoding/xml"
)

//C:\Program Files\Go\src\facecat
//set GOPROXY=https://goproxy.cn,direct
/*
* 坐标结构
*/
type FCPoint struct {
   X float64 //横坐标
   Y float64 //纵坐标
   IsNotEmpty bool //是否不为空
}

func CreatePoint(dx float64, dy float64) FCPoint{
	point := FCPoint{X:dx, Y:dy}
    point.IsNotEmpty = true
    return point
}

/*
* 大小结构
*/
type FCSize struct {
   Cx float64 //长
   Cy float64 //宽
   IsNotEmpty bool //是否不为空
}

func CreateSize(dcx float64, dcy float64) FCSize{
	size := FCSize{Cx:dcx, Cy:dcy}
    size.IsNotEmpty = true
    return size
}

/*
* 矩形结构
*/
type FCRect struct {
   Left float64 //左侧
   Top float64 //上侧
   Right float64 //右侧
   Bottom float64 //底部
   IsNotEmpty bool //是否不为空
}

func CreateRect(dleft float64, dtop float64, dright float64, dbottom float64) FCRect{
    rect := FCRect{Left:dleft, Top:dtop, Right:dright, Bottom:dbottom}
    rect.IsNotEmpty = true
	return rect
}

/*
* 边距信息
*/
type FCPadding struct {
   Left float64 //左侧
   Top float64 //上侧
   Right float64 //右侧
   Bottom float64 //底部
   IsNotEmpty bool //是否不为空
}

func CreatePadding(dleft float64, dtop float64, dright float64, dbottom float64) FCPadding{
	padding := FCPadding{Left:dleft, Top:dtop, Right:dright, Bottom:dbottom}
    padding.IsNotEmpty = true
    return padding
}

//字符串转换成float64
func ConvertToFloat64(str string)float64{
    if len(str) > 0{
	    floatvar, _ := strconv.ParseFloat(str, 64)
	    return floatvar
    }else{
        return 0
    }
}

//字符串转换成int
func ConvertToInt(str string)int{
	intvar, _ := strconv.ParseInt(str, 10, 32)
	return int(intvar)
}

//字符串转换成int
func ConvertToInt64(str string)int64{
	intvar, _ := strconv.ParseInt(str, 10, 64)
	return int64(intvar)
}

/*
* float64转换成字符串
*/
func ConvertFloat64ToStr(value float64)(string){
    return fmt.Sprintf("%f", value)
}

/*
* int转换成字符串
*/
func ConvertIntToStr(value int)(string){
    return strconv.Itoa(value)
}

/*
* 转换颜色
*/
func ToColor(str string)(int64){
    newStr := strings.Replace(str, "(", "", -1)
    newStr = strings.Replace(newStr, ")", "", -1)
    if strings.Contains(newStr, "rgba"){
        newStr = strings.Replace(newStr, "rgba", "", -1)
        strs := strings.Split(newStr, ",")
        r := ConvertToInt(strs[0])
        g := ConvertToInt(strs[1])
        b := ConvertToInt(strs[2])
        a := ConvertToInt(strs[3])
        rgb := ((r | (g << 8)) | (b << 0x10))
        if (a == 255) {
            return int64(rgb)
        }else if (a == 0) {
            return -2000000000
        }else {
            return -int64(rgb * 1000 + a)
        }
    }else if strings.Contains(newStr, "rgb"){
        newStr = strings.Replace(newStr, "rgb", "", -1)
        strs := strings.Split(newStr, ",")
        r := ConvertToInt(strs[0])
        g := ConvertToInt(strs[1])
        b := ConvertToInt(strs[2])
        rgb := ((r | (g << 8)) | (b << 0x10))
        return int64(rgb)
    }else if len(str) > 0 && str != "none"{
        return ConvertToInt64(str)
    }
    return 0
}
type ClickGridCellEventCallBack func(grid *FCView, row *FCGridRow, gridColumn *FCGridColumn, cell *FCGridCell, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int)
type ClickGridColumnEventCallBack func(grid *FCView, gridColumn *FCGridColumn, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int)
type ClickTreeNodeEventCallBack func(tree *FCView, node *FCTreeNode, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int)
type CalculateChartMaxMinEventCallBack func(chart *FCView)
type InvalidateViewEventCallBack func(view *FCView)
type InvalidateEventCallBack func(paint *FCPaint)
type KeyEventCallBack func(view *FCView, key int)
type MouseEventCallBack func(view *FCView, mp FCPoint, buttons int, clicks int, delta int)
type ClickEventCallBack func(view *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int)
type PaintEventCallBack func(view *FCView, paint *FCPaint, clipRect FCRect)
type PaintGridCellEventCallBack func(grid *FCView, row *FCGridRow, column *FCGridColumn, cell *FCGridCell, paint *FCPaint, left float64, top float64, right float64, bottom float64)
type PaintGridColumnEventCallBack func(grid *FCView, column *FCGridColumn, paint *FCPaint, left float64, top float64, right float64, bottom float64)
type PaintTreeNodeEventCallBack func(tree *FCView, row *FCTreeRow, column *FCTreeColumn, node *FCTreeNode, paint *FCPaint, left float64, top float64, right float64, bottom float64)
type PaintCalendarDayButtonEventCallBack func(calendar *FCView, dayButton *DayButton, paint *FCPaint)
type PaintCalendarMonthButtonEventCallBack func(calendar *FCView, monthButton *MonthButton, paint *FCPaint)
type PaintCalendarYearButtonEventCallBack func(calendar *FCView, yearButton *YearButton, paint *FCPaint)
type PaintCalendarHeadDivEventCallBack func(calendar *FCView, headDiv *HeadDiv, paint *FCPaint)
type RenderViewsEventCallBack func(views []*FCView, paint *FCPaint, clipRect FCRect)
type UpdateViewEventCallBack func(views []*FCView)
type WndProcCallBack func(hwnd HWND, msg uint32, wParam, lParam uintptr)(result uintptr)
type ContainsPointCallBack func(view *FCView, mp FCPoint)(bool)
/*
* 绘图结构
*/
type FCPaint struct{
    OnCalculateMaxMin CalculateChartMaxMinEventCallBack
    OnClick ClickEventCallBack
    OnClickGridCell ClickGridCellEventCallBack
    OnClickGridColumn ClickGridColumnEventCallBack
    OnClickTreeNode ClickTreeNodeEventCallBack
    OnContainsPoint ContainsPointCallBack
    OnInvalidateView InvalidateViewEventCallBack
    OnInvalidate InvalidateEventCallBack
    OnKeyDown KeyEventCallBack
    OnKeyUp KeyEventCallBack
    OnChar KeyEventCallBack
    OnMouseDown MouseEventCallBack
    OnMouseMove MouseEventCallBack
    OnMouseUp MouseEventCallBack
    OnMouseWheel MouseEventCallBack
    OnMouseEnter MouseEventCallBack
    OnMouseLeave MouseEventCallBack
    OnPaint PaintEventCallBack
    OnPaintBorder PaintEventCallBack
    OnPaintCalendarDayButton PaintCalendarDayButtonEventCallBack
    OnPaintCalendarMonthButton PaintCalendarMonthButtonEventCallBack
    OnPaintCalendarYearButton PaintCalendarYearButtonEventCallBack
    OnPaintCalendarHeadDiv PaintCalendarHeadDivEventCallBack
    OnPaintChartScale PaintEventCallBack
    OnPaintChartHScale PaintEventCallBack
    OnPaintChartStock PaintEventCallBack
    OnPaintChartPlot PaintEventCallBack
    OnPaintChartCrossLine PaintEventCallBack
    OnPaintGridCell PaintGridCellEventCallBack
    OnPaintGridColumn PaintGridColumnEventCallBack
    OnPaintTreeNode PaintTreeNodeEventCallBack
    OnRenderViews RenderViewsEventCallBack
    OnUpdateView UpdateViewEventCallBack 
    AllowPartialPaint bool //是否允许局部绘图
    CancelClick bool //是否退出点击
    DefaultUIStyle string //默认样式
    DragBeginPoint FCPoint //拖动开始时的触摸位置
    DragBeginRect FCRect //拖动开始时的区域
    DraggingView []*FCView  //正被拖动的控件
    FocusedView []*FCView //焦点视图
    GdiPlus *GdiPlusPaint
    HDC HDC
    HWnd HWND
    IsDoubleClick bool
    IsNotEmpty bool //是否不为空
    ResizeColumnState int //改变列宽度的状态
    ResizeColumnBeginWidth float64 //改变列宽度的起始值
    ResizeColumnIndex int //改变列宽度的索引
    ScaleFactorX float64 //横向缩放比例
    ScaleFactorY float64 //纵向缩放比例
    Size FCSize //尺寸
    SystemFont string
    TouchDownPoint FCPoint //鼠标按下时的坐标
    TouchDownView []*FCView //鼠标按下的视图
    TouchMoveView []*FCView//鼠标移动的视图
    Views []*FCView //子视图
    TextSizeCache map[string]FCSize //日历
}

/*
* 初始化
*/
func CreatePaint()(*FCPaint){
    paint := new(FCPaint)
    paint.IsNotEmpty = true
    paint.AllowPartialPaint = false
    paint.ScaleFactorX = 1
    paint.ScaleFactorY = 1
    paint.ResizeColumnIndex = -1
    paint.GdiPlus = new(GdiPlusPaint)
    paint.SystemFont = "SimSun"
    paint.DefaultUIStyle = "light"
    paint.TextSizeCache = make(map[string]FCSize)
    return paint
}

func (c *FCPaint)GetTouchDownView()(*FCView){
    length := len(c.TouchDownView)
    if length > 0{
        return c.TouchDownView[0]
    }else{
        noneView :=new(FCView)
        noneView.IsNotEmpty = false
        return noneView
    }
}

func (c *FCPaint)SetTouchDownView(view *FCView){
    var pList []*FCView
    c.TouchDownView = pList
    c.TouchDownView = append(c.TouchDownView, view)
}

func (c *FCPaint)GetTouchMoveView()(*FCView){
    length := len(c.TouchMoveView)
    if length > 0{
        return c.TouchMoveView[0]
    }else{
        noneView := new(FCView)
        noneView.IsNotEmpty = false
        return noneView
    }
}

func (c *FCPaint)SetTouchMoveView(view *FCView){
    var pList []*FCView
    c.TouchMoveView = pList
    c.TouchMoveView = append(c.TouchMoveView, view)
}

func (c *FCPaint)GetFocusedView()(*FCView){
    length := len(c.FocusedView)
    if length > 0{
        return c.FocusedView[0]
    }else{
        noneView := new(FCView)
        noneView.IsNotEmpty = false
        return noneView
    }
}

func (c *FCPaint)SetFocusedView(view *FCView){
    var pList []*FCView
    c.FocusedView = pList
    c.FocusedView = append(c.FocusedView, view)
}

func (c *FCPaint)GetDraggingView()(*FCView){
    length := len(c.DraggingView)
    if length > 0{
        return c.DraggingView[0]
    }else{
        noneView := new(FCView)
        noneView.IsNotEmpty = false
        return noneView
    }
}

func (c *FCPaint)SetDraggingView(view *FCView){
    var pList []*FCView
    c.DraggingView = pList
    c.DraggingView = append(c.DraggingView, view)
}

 /*
* 开始绘图
* rect:区域
*/
func (c *FCPaint)BeginPaint(rect FCRect, pRect FCRect){
    c.GdiPlus.beginPaint(c.HDC, rect.Left, rect.Top, rect.Right, rect.Bottom, pRect.Left, pRect.Top, pRect.Right, pRect.Bottom)
}
/*
* 绘制线
* color:颜色
* width:宽度
* style:样式
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
*/
func (c *FCPaint)DrawLine(color string, width float64, style float64, x1 float64, y1 float64, x2 float64, y2 float64){
    wd := math.Min(c.ScaleFactorX, c.ScaleFactorY) * width
	if wd < 1{
		wd = 1
    }
    inStyle := int(style)
    c.GdiPlus.drawLine(ToColor(color), wd, inStyle, x1, y1, x2, y2)
}
/*
*绘制连续线
*color:颜色 
*width:宽度 
*style:样式 
*/
func (c *FCPaint)DrawPolyline(color string, width float64, style float64, apt []FCPoint){
    wd := math.Min(c.ScaleFactorX, c.ScaleFactorY) * width
	if wd < 1{
		wd = 1
    }
    inStyle := int(style)
    strApt := ""
    for i := 0; i < len(apt); i++ {
        strApt += strconv.Itoa(int(apt[i].X)) + "," + strconv.Itoa(int(apt[i].Y))
		if i != len(apt) - 1{
			strApt += " "
        }
    }
	c.GdiPlus.drawPolyline(ToColor(color), wd, inStyle, strApt)
}
/*
*绘制多边形
*color:颜色 
*width:宽度 
*style:样式 
*/
func (c *FCPaint)DrawPolygon(color string, width float64, style float64, apt []FCPoint){
    wd := math.Min(c.ScaleFactorX, c.ScaleFactorY) * width
	if wd < 1{
		wd = 1
    }
    inStyle := int(style)
    strApt := ""
    for i := 0; i < len(apt); i++ {
        strApt += strconv.Itoa(int(apt[i].X)) + "," + strconv.Itoa(int(apt[i].Y))
		if i != len(apt) - 1{
			strApt += " "
        }
    }
	c.GdiPlus.drawPolygon(ToColor(color), wd, inStyle, strApt)
}
 /*
* 绘制矩形
* color:颜色
* width:宽度
* style:样式
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func (c *FCPaint)DrawRect(color string, width float64, style float64, left float64, top float64, right float64, bottom float64){
    wd := math.Min(c.ScaleFactorX, c.ScaleFactorY) * width
	if wd < 1{
		wd = 1
    }
    inStyle := int(style)
    c.GdiPlus.drawRect(ToColor(color), wd, inStyle, left, top, right, bottom)
}
/*
* 绘制矩形
* color:颜色
* width:宽度
* style:样式
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
* cornerRadius:圆角
*/
func (c *FCPaint)DrawRoundRect(color string, width float64, style float64, left float64, top float64, right float64, bottom float64, cornerRadius float64){
    wd := math.Min(c.ScaleFactorX, c.ScaleFactorY) * width
	if wd < 1{
		wd = 1
    }
    inStyle := int(style)
    if cornerRadius > 0{
        c.GdiPlus.drawRoundRect(ToColor(color), wd, inStyle, left, top, right, bottom, cornerRadius)
    }else{
        c.GdiPlus.drawRect(ToColor(color), wd, inStyle, left, top, right, bottom)
    }
}
/*
* 绘制椭圆
* color:颜色
* width:宽度
* style:样式
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func (c *FCPaint)DrawEllipse(color string, width float64, style float64, left float64, top float64, right float64, bottom float64){
    wd := math.Min(c.ScaleFactorX, c.ScaleFactorY) * width
	if wd < 1{
		wd = 1
    }
    inStyle := int(style)
    c.GdiPlus.drawEllipse(ToColor(color), wd, inStyle, left, top, right, bottom)
}
 /*
* 绘制文字
* text:文字
* color:颜色
* font:字体
* x:横坐标
* y:纵坐标
*/
func (c *FCPaint)DrawText(text string, color string, font string, x float64, y float64){
    newFont := strings.Replace(font, "Default", c.SystemFont, -1)
    c.GdiPlus.drawTextWithPos(text, ToColor(color), newFont, x, y)

}
/*
* 结束绘图
*/
func (c *FCPaint)EndPaint(){
    c.GdiPlus.endPaint()
}
/*
*绘制多边形
*color:颜色 
*apt:坐标
*/
func (c *FCPaint)FillPolygon(color string, apt []FCPoint){
    strApt := ""
    for i := 0; i < len(apt); i++ {
        strApt += strconv.Itoa(int(apt[i].X)) + "," + strconv.Itoa(int(apt[i].Y))
		if i != len(apt) - 1{
			strApt += " "
        }
    }
    c.GdiPlus.fillPolygon(ToColor(color), strApt)			
}
/*
* 填充矩形
* color:颜色
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func (c *FCPaint)FillRect(color string, left float64, top float64, right float64, bottom float64){
    c.GdiPlus.fillRect(ToColor(color), left, top, right, bottom)
}
/*
* 填充矩形
* color:颜色
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
* cornerRadius:圆角
*/
func (c *FCPaint)FillRoundRect(color string, left float64, top float64, right float64, bottom float64, cornerRadius float64){
    if cornerRadius > 0{
        c.GdiPlus.fillRoundRect(ToColor(color), left, top, right, bottom, cornerRadius)
    }else{
        c.GdiPlus.fillRect(ToColor(color), left, top, right, bottom)
    }
}
/*
* 填充椭圆
* color:颜色
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func (c *FCPaint)FillEllipse(color string, left float64, top float64, right float64, bottom float64){
    c.GdiPlus.fillEllipse(ToColor(color), left, top, right, bottom)
}
/*
* 裁剪
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func (c *FCPaint)SetClip(left float64, top float64, right float64, bottom float64){
    c.GdiPlus.setClip(left, top, right, bottom)
}
/*
* 设置偏移量
* offsetX:横向偏移
* offsetY:纵向偏移
*/
func (c *FCPaint)SetOffset(x float64, y float64){
    c.GdiPlus.setOffset(x, y)
}
/*
* 获取字体大小
* text:文字
* font:字体
*/
func (c *FCPaint)TextSize(text string, font string)(FCSize){
    newFont := strings.Replace(font, "Default", c.SystemFont, -1)
    key := text + newFont
    size, ok := c.TextSizeCache[key]
    if ok {
        return size
    }else{
        strSize := c.GdiPlus.textSize(text, newFont, -1)
        results := strings.Split(strSize, ",")
        tSize := CreateSize(ConvertToFloat64(results[0]), ConvertToFloat64(results[1]))
        c.TextSizeCache[key] = tSize
        return tSize
    }
}
/*
* 绘制文字
* text:文字
* color:颜色
* font:字体
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func (c *FCPaint)DrawTextAutoEllipsis(text string, color string, font string, left float64, top float64, right float64, bottom float64){
    if len(text) != 0 {
		tSize := c.TextSize(text, font)
		if (tSize.Cx < right - left) {
			c.DrawText(text, color, font, left, top)
		} else {
			if tSize.Cx > 0 {
				subLen := 3
				for {
					newLen := len(text) - subLen
					if (newLen > 0) {
						newText := text[0:newLen] + "..."
						tSize = c.TextSize(newText, font)
						if tSize.Cx < right - left {
							c.DrawText(newText, color, font, left, top)
							break;
						} else {
							subLen += 3
						}
					} else {
						break
					}
				}
			}
		}
	}
}

//从byte转化成uintptr
func ByteToPtr(n byte) uintptr {
	return uintptr(n)
}

//从uintptr转换成int
func IntToPtr(n int) uintptr {
	return uintptr(n)
}

//从uintptr转换成float32
func Float32ToPtr(n float32)uintptr{
	return uintptr(math.Float32bits(n))
}

//从uintptr转换成float64
func FloatToPtr(n float64)uintptr{
	return uintptr(math.Float64bits(n))
}

//从uintptr转换成int64
func Int64ToPtr(n int64)uintptr{
	return uintptr(n)
}

//从string转换成uintptr
func StringToUintPtr(val string) uintptr {
    return uintptr(unsafe.Pointer(syscall.StringBytePtr(val)))
}

//转换成UTF-8
func U16To8(u16 []byte) string {
	if len(u16)%2 != 0 {
		return ""
	}
	var body bytes.Buffer
	for i := 0; i < len(u16)/2; i++ {
		v := int(u16[2*i]) + int(u16[2*i+1])<<8
		if v <= 127 {
			body.WriteByte(byte(v))
		} else if v <= 2047 {
			a1 := byte(v&63) + 128
			v = v >> 6
			a2 := byte(v&31) + 192
			body.WriteByte(a2)
			body.WriteByte(a1)
 
		} else if v <= 65535 {
			a1 := byte(v&63) + 128
			v = v >> 6
			a2 := byte(v&63) + 128
			v = v >> 6
			a3 := byte(v&15) + 224
			body.WriteByte(a3)
			body.WriteByte(a2)
			body.WriteByte(a1)
		}
	}
	return string(body.Bytes())
}

//从uintptr转换成String
func StringFromPtr(sptr uintptr) (res string) {
	if sptr <= 0 {
		return
	}
	buf := make([]byte, 0)
	for i := 0; *(*byte)(unsafe.Pointer(sptr + uintptr(i))) != 0; i++ {
		buf = append(buf, *(*byte)(unsafe.Pointer(sptr + uintptr(i))))
	}

	return string(buf)
}

//从uintptr转换成String
func StringFromPtrUTF8(sptr uintptr) (res string) {
	if sptr <= 0 {
		return
	}
	buf := make([]byte, 0)
	for i := 0; *(*byte)(unsafe.Pointer(sptr + uintptr(i))) != 0; i++ {
		buf = append(buf, *(*byte)(unsafe.Pointer(sptr + uintptr(i))))
	}

	return U16To8(buf)
}

//从uintptr转换成Bool
func GoBool(val uintptr) bool {
	if val != 0 {
		return true
	}
	return false
}

var g_dll,g_err = syscall.LoadDLL("facecatcpp.dll")
var procCreateGdiPlus,_ = g_dll.FindProc("createGdiPlus")
var procDeleteGdiPlus,_ = g_dll.FindProc("deleteGdiPlus")
var procAddArcGdiPlus,_ = g_dll.FindProc("addArcGdiPlus")
var procAddBezierGdiPlus,_ = g_dll.FindProc("addBezierGdiPlus")
var procAddCurveGdiPlus,_ = g_dll.FindProc("addCurveGdiPlus")
var procAddEllipseGdiPlus,_ = g_dll.FindProc("addEllipseGdiPlus")
var procAddLineGdiPlus,_ = g_dll.FindProc("addLineGdiPlus")
var procAddRectGdiPlus,_ = g_dll.FindProc("addRectGdiPlus")
var procAddPieGdiPlus,_ = g_dll.FindProc("addPieGdiPlus")
var procAddTextGdiPlus,_ = g_dll.FindProc("addTextGdiPlus")
var procBeginExportGdiPlus,_ = g_dll.FindProc("beginExportGdiPlus")
var procBeginPaintGdiPlus,_ = g_dll.FindProc("beginPaintGdiPlus")
var procBeginPathGdiPlus,_ = g_dll.FindProc("beginPathGdiPlus")
var procClipPathGdiPlus,_ = g_dll.FindProc("clipPathGdiPlus")
var procClearCachesGdiPlus,_ = g_dll.FindProc("clearCachesGdiPlus")
var procCloseFigureGdiPlus,_ = g_dll.FindProc("closeFigureGdiPlus")
var procClosePathGdiPlus,_ = g_dll.FindProc("closePathGdiPlus")
var procDrawArcGdiPlus,_ = g_dll.FindProc("drawArcGdiPlus")
var procDrawBezierGdiPlus,_ = g_dll.FindProc("drawBezierGdiPlus")
var procDrawCurveGdiPlus,_ = g_dll.FindProc("drawCurveGdiPlus")
var procDrawEllipseGdiPlus,_ = g_dll.FindProc("drawEllipseGdiPlus")
var procDrawImageGdiPlus,_ = g_dll.FindProc("drawImageGdiPlus")
var procDrawLineGdiPlus,_ = g_dll.FindProc("drawLineGdiPlus")
var procDrawPathGdiPlus,_ = g_dll.FindProc("drawPathGdiPlus")
var procDrawPieGdiPlus,_ = g_dll.FindProc("drawPieGdiPlus")
var procDrawPolygonGdiPlus,_ = g_dll.FindProc("drawPolygonGdiPlus")
var procDrawPolylineGdiPlus,_ = g_dll.FindProc("drawPolylineGdiPlus")
var procDrawRectGdiPlus,_ = g_dll.FindProc("drawRectGdiPlus")
var procDrawRoundRectGdiPlus,_ = g_dll.FindProc("drawRoundRectGdiPlus")
var procDrawTextGdiPlus2,_ = g_dll.FindProc("drawTextGdiPlus")
var procDrawTextWithPosGdiPlus2,_ = g_dll.FindProc("drawTextWithPosGdiPlus")
var procDrawTextAutoEllipsisGdiPlus2,_ = g_dll.FindProc("drawTextAutoEllipsisGdiPlus2")
var proEndExportGdiPlusc,_ = g_dll.FindProc("endExportGdiPlus")
var procEndPaintGdiPlus,_ = g_dll.FindProc("endPaintGdiPlus")
var procExcludeClipPathGdiPlus,_ = g_dll.FindProc("excludeClipPathGdiPlus")
var procFillEllipseGdiPlus,_ = g_dll.FindProc("fillEllipseGdiPlus")
var procFillGradientEllipseGdiPlus,_ = g_dll.FindProc("fillGradientEllipseGdiPlus")
var procFillGradientPathGdiPlus,_ = g_dll.FindProc("fillGradientPathGdiPlus")
var procFillGradientPolygonGdiPlus,_ = g_dll.FindProc("fillGradientPolygonGdiPlus")
var procFillGradientRectGdiPlus,_ = g_dll.FindProc("fillGradientRectGdiPlus")
var procFillPathGdiPlus,_ = g_dll.FindProc("fillPathGdiPlus")
var procFillPieGdiPlus,_ = g_dll.FindProc("fillPieGdiPlus")
var procFillPolygonGdiPlus,_ = g_dll.FindProc("fillPolygonGdiPlus")
var procFillRectGdiPlus,_ = g_dll.FindProc("fillRectGdiPlus")
var procFillRoundRectGdiPlus,_ = g_dll.FindProc("fillRoundRectGdiPlus")
var procSetClipGdiPlus,_ = g_dll.FindProc("setClipGdiPlus")
var procSetLineCapGdiPlus,_ = g_dll.FindProc("setLineCapGdiPlus")
var procSetOffsetGdiPlus,_ = g_dll.FindProc("setOffsetGdiPlus")
var procSetOpacityGdiPlus,_ = g_dll.FindProc("setOpacityGdiPlus")
var procSetResourcePathGdiPlus,_ = g_dll.FindProc("setResourcePathGdiPlus")
var procSetRotateAngleGdiPlus,_ = g_dll.FindProc("setRotateAngleGdiPlus")
var procSetScaleFactorGdiPlus,_ = g_dll.FindProc("setScaleFactorGdiPlus")
var procTextSizeGdiPlus2,_ = g_dll.FindProc("textSizeGdiPlus")
var procOnMessage,_ = g_dll.FindProc("onMessage")
var procCreateView,_ = g_dll.FindProc("createView")
var procSetAttribute2,_ = g_dll.FindProc("setAttribute2")
var procGetAttribute,_ = g_dll.FindProc("getAttribute")
var procPaintView,_ = g_dll.FindProc("paintView")
var procFocusView,_ = g_dll.FindProc("focusView")
var procUnFocusView,_ = g_dll.FindProc("unFocusView")
var procMouseDownView,_ = g_dll.FindProc("mouseDownView")
var procMouseUpView,_ = g_dll.FindProc("mouseUpView")
var procMouseMoveView,_ = g_dll.FindProc("mouseMoveView")
var procMouseWheelView,_ = g_dll.FindProc("mouseWheelView")
var procSetCursor,_ = g_dll.FindProc("setCursor")
var procRemoveView,_ = g_dll.FindProc("removeView")
var procPumpMessage,_ = g_dll.FindProc("pumpMessage")

/*
* 调用Gdi+的DLL
*/
type GdiPlusPaint struct{
    gID int
}

/*
*创建GDI+
*/
func (c *GdiPlusPaint)createGdiPlus(hWnd HWND){
	result,_,_ := procCreateGdiPlus.Call(IntToPtr(int(hWnd)))
    c.gID = int(result)
}
/*
*销毁GDI+
*/
func (c *GdiPlusPaint)deleteGdiPlus(){
	procDeleteGdiPlus.Call(IntToPtr(c.gID))
}
/* 
*添加曲线
*rect 矩形区域
*startAngle 从x轴到弧线的起始点沿顺时针方向度量的角（以度为单位）
*sweepAngle 从startAngle参数到弧线的结束点沿顺时针方向度量的角（以度为单位）
*/
func (c *GdiPlusPaint)addArc(left float64, top float64, right float64, float64, bottom float64, startAngle float64, sweepAngle float64){
	procAddArcGdiPlus.Call(IntToPtr(c.gID), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), Float32ToPtr(float32(startAngle)), Float32ToPtr(float32(sweepAngle)))
}
/*
*添加贝赛尔曲线
*strApt 点阵字符串 x1,y1 x2,y2...
*/
func (c *GdiPlusPaint)addBezier(strApt string){
    procAddBezierGdiPlus.Call(IntToPtr(c.gID), StringToUintPtr(strApt))
}
/*
*添加曲线
*strApt 点阵字符串 x1,y1 x2,y2...
*/
func (c *GdiPlusPaint)addCurve(strApt string){
    procAddCurveGdiPlus.Call(IntToPtr(c.gID), StringToUintPtr(strApt))
}
/*
*添加椭圆
*rect 矩形
*/
func (c *GdiPlusPaint)addEllipse(left float64, top float64, right float64, bottom float64){
	procAddEllipseGdiPlus.Call(IntToPtr(c.gID), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))
}
/*
*添加直线
*x1 第一个点的横坐标
*y1 第一个点的纵坐标（以度为单位）
*x2 第二个点的横坐标
*y2 第二个点的纵坐标
*/
func (c *GdiPlusPaint)addLine(x1 float64, y1 float64, x2 float64, y2 float64){
	procAddLineGdiPlus.Call(IntToPtr(c.gID), IntToPtr(int(x1)), IntToPtr(int(y1)), IntToPtr(int(x2)), IntToPtr(int(y2)))
}
/*
*添加矩形
*rect 区域
*/
func (c *GdiPlusPaint)addRect(left float64, top float64, right float64, bottom float64){
	procAddRectGdiPlus.Call(IntToPtr(c.gID), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))
}
/*
*添加扇形
*rect 矩形区域
*startAngle 从x轴到弧线的起始点沿顺时针方向度量的角（以度为单位）
*sweepAngle 从startAngle参数到弧线的结束点沿顺时针方向度量的角（以度为单位）
*/
func (c *GdiPlusPaint)addPie(left float64, top float64, right float64, bottom float64, startAngle float64, sweepAngle float64){
	procAddPieGdiPlus.Call(IntToPtr(c.gID), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), Float32ToPtr(float32(startAngle)), Float32ToPtr(float32(sweepAngle)))
}
/*
*添加文字
*text 文字
*font 字体
*rect 区域
*/
func (c *GdiPlusPaint)addText(text string, font string, left float64, top float64, right float64, bottom float64, width float64){
	procAddTextGdiPlus.Call(IntToPtr(c.gID), StringToUintPtr(text), StringToUintPtr(font), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), IntToPtr(int(width)))
}
/*
*开始导出
*exportPath  路径
*rect 区域
*/
func (c *GdiPlusPaint)beginExport(exportPath string, left float64, top float64, right float64, bottom float64){
	procBeginExportGdiPlus.Call(IntToPtr(c.gID), StringToUintPtr(exportPath), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))
}
/*
*开始绘图
*hdc HDC
*wRect 窗体区域
*pRect 刷新区域
*/
func (c *GdiPlusPaint)beginPaint(hDC HDC, wLeft float64, wTop float64, wRight float64, wBottom float64, pLeft float64, pTop float64, pRight float64, pBottom float64){	
    procBeginPaintGdiPlus.Call(IntToPtr(c.gID), IntToPtr(int(hDC)), IntToPtr(int(wLeft)), IntToPtr(int(wTop)), IntToPtr(int(wRight)), IntToPtr(int(wBottom)), IntToPtr(int(pLeft)), IntToPtr(int(pTop)), IntToPtr(int(pRight)), IntToPtr(int(pBottom)))
}
/*
*开始一段路径
*/
func (c *GdiPlusPaint)beginPath(){	
    procBeginPathGdiPlus.Call(IntToPtr(c.gID))
}
/*
*裁剪路径
*/
func (c *GdiPlusPaint)clipPath(){	
    procClipPathGdiPlus.Call(IntToPtr(c.gID))
}
/*
*清除缓存
*/
func (c *GdiPlusPaint)clearCaches(){	
    procClearCachesGdiPlus.Call(IntToPtr(c.gID))
}
/*
*闭合路径
*/
func (c *GdiPlusPaint)closeFigure(){
    procCloseFigureGdiPlus.Call(IntToPtr(c.gID))
}
/*
*结束一段路径
*/
func (c *GdiPlusPaint)closePath(){	
    procClosePathGdiPlus.Call(IntToPtr(c.gID))
}
/*
*绘制弧线
*dwPenColor 颜色
*width 宽度
*style 样式
*rect 矩形区域
*startAngle 从x轴到弧线的起始点沿顺时针方向度量的角（以度为单位）
*sweepAngle 从startAngle参数到弧线的结束点沿顺时针方向度量的角（以度为单位）
*/
func (c *GdiPlusPaint)drawArc(dwPenColor int64, width float64, style int, left float64, top float64, right float64, bottom float64, startAngle float64, sweepAngle float64){	
    procDrawArcGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), Float32ToPtr(float32(startAngle)), Float32ToPtr(float32(sweepAngle)))
}
/*
*设置贝赛尔曲线
*dwPenColor 颜色
*width 宽度
*style 样式
*strApt 点阵字符串 x1,y1 x2,y2...
*/
func (c *GdiPlusPaint)drawBezier(dwPenColor int64, width float64, style int, strApt string){		
    procDrawBezierGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style), StringToUintPtr(strApt))
}
/*
*绘制曲线
*dwPenColor 颜色
*width 宽度
*style 样式
*strApt 点阵字符串 x1,y1 x2,y2...
*/
func (c *GdiPlusPaint)drawCurve(dwPenColor int64, width float64, style int, strApt string){		
    procDrawCurveGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style), StringToUintPtr(strApt))
}
/*
*绘制椭圆
*dwPenColor 颜色
*width 宽度
*style 样式
*left 左侧坐标
*top 顶部左标
*right 右侧坐标
*bottom 底部坐标
*/
func (c *GdiPlusPaint)drawEllipse(dwPenColor int64, width float64, style int, left float64, top float64, right float64, bottom float64){		
    procDrawEllipseGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))	
}
/*
*绘制图片
*imagePath 图片路径
*rect 绘制区域
*/
func (c *GdiPlusPaint)drawImage(imagePath string, left float64, top float64, right float64, bottom float64){
    procDrawImageGdiPlus.Call(IntToPtr(c.gID), StringToUintPtr(imagePath), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))	
}
/*
*绘制直线
*dwPenColor 颜色
*width 宽度
*style 样式
*x1 第一个点的横坐标
*y1 第一个点的纵坐标
*x2 第二个点的横坐标
*y2 第二个点的纵坐标
*/
func (c *GdiPlusPaint)drawLine(dwPenColor int64, width float64, style int, x1 float64, y1 float64, x2 float64, y2 float64){		
    procDrawLineGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style), IntToPtr(int(x1)), IntToPtr(int(y1)), IntToPtr(int(x2)), IntToPtr(int(y2)))	
}
/*
*绘制直线
*dwPenColor 颜色
*width 宽度
*style 样式
*/
func (c *GdiPlusPaint)drawPath(dwPenColor int64, width float64, style int){	
    procDrawPathGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style))
}
/*
*绘制扇形
*dwPenColor 颜色
*width 宽度
*style 样式
rect 矩形区域
*startAngle 从x轴到弧线的起始点沿顺时针方向度量的角（以度为单位）
*sweepAngle 从startAngle参数到弧线的结束点沿顺时针方向度量的角（以度为单位）
*/
func (c *GdiPlusPaint)drawPie(dwPenColor int64, width float64, style int, left float64, top float64, right float64, bottom float64, startAngle float64, sweepAngle float64){		
    procDrawPieGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), Float32ToPtr(float32(startAngle)), Float32ToPtr(float32(sweepAngle)))
}
/*
*绘制多边形
*dwPenColor 颜色
*width 宽度
*style 样式
*strApt 点阵字符串 x1,y1 x2,y2...
*/
func (c *GdiPlusPaint)drawPolygon(dwPenColor int64, width float64, style int, strApt string){	
    procDrawPolygonGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style), StringToUintPtr(strApt))
}
/*
*绘制大量直线
*dwPenColor 颜色
*width 宽度
*style 样式
*strApt 点阵字符串 x1,y1 x2,y2...
*/
func (c *GdiPlusPaint)drawPolyline(dwPenColor int64, width float64, style int, strApt string){		
    procDrawPolylineGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style), StringToUintPtr(strApt))
}
/*
*绘制矩形
*dwPenColor 颜色
*width 宽度
*style 样式
*rect 矩形区域
*/
func (c *GdiPlusPaint)drawRect(dwPenColor int64, width float64, style int, left float64, top float64, right float64, bottom float64){	
    procDrawRectGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))	
}
/*
*绘制圆角矩形
*dwPenColor 颜色
*width 宽度
*style 样式
*rect 矩形区域
*cornerRadius 边角半径
*/
func (c *GdiPlusPaint)drawRoundRect(dwPenColor int64, width float64, style int, left float64, top float64, right float64, bottom float64, cornerRadius float64){		
    procDrawRoundRectGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), Float32ToPtr(float32(width)), IntToPtr(style), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), IntToPtr(int(cornerRadius)))	
}
/*
*绘制文字
*text 文字
*dwPenColor 颜色
*font 字体
*rect 矩形区域
*/
func (c *GdiPlusPaint)drawText(strText string, dwPenColor int64, font string, left float64, top float64, right float64, bottom float64, width float64){		
    procDrawTextGdiPlus2.Call(IntToPtr(c.gID), StringToUintPtr(strText), Int64ToPtr(dwPenColor), StringToUintPtr(font), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), IntToPtr(int(width)))	
}
/*
*绘制文字
*text 文字
*dwPenColor 颜色
*font 字体
*rect 矩形区域
*/
func (c *GdiPlusPaint)drawTextWithPos(strText string, dwPenColor int64, font string, x float64, y float64){		
    procDrawTextWithPosGdiPlus2.Call(IntToPtr(c.gID), StringToUintPtr(strText), Int64ToPtr(dwPenColor), StringToUintPtr(font), IntToPtr(int(x)), IntToPtr(int(y)))
}
/*
*绘制自动省略结尾的文字
*text 文字
*dwPenColor 颜色
*font 字体
*rect 矩形区域
*/
func (c *GdiPlusPaint)drawTextAutoEllipsis(strText string, dwPenColor int64, font string, left float64, top float64, right float64, bottom float64){		
    procDrawTextAutoEllipsisGdiPlus2.Call(IntToPtr(c.gID), StringToUintPtr(strText), Int64ToPtr(dwPenColor), StringToUintPtr(font), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))	
}
/*
*结束导出
*/
func (c *GdiPlusPaint)endExport(){		
    proEndExportGdiPlusc.Call(IntToPtr(c.gID))
}
/*
*结束绘图
*/
func (c *GdiPlusPaint)endPaint(){		
    procEndPaintGdiPlus.Call(IntToPtr(c.gID))
}
/*
*反裁剪路径
*/
func (c *GdiPlusPaint)excludeClipPath(){	
    procExcludeClipPathGdiPlus.Call(IntToPtr(c.gID))
}
/*
*填充椭圆
*dwPenColor 颜色
*rect 矩形区域
*/
func (c *GdiPlusPaint)fillEllipse(dwPenColor int64, left float64, top float64, right float64, bottom float64){		
    procFillEllipseGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))
}
/*
*绘制渐变椭圆
*dwFirst 开始颜色
*dwSecond  结束颜色
*rect 矩形区域
*angle 角度
*/
func (c *GdiPlusPaint)fillGradientEllipse(dwFirst int64, dwSecond int64, left float64, top float64, right float64, bottom float64, angle float64){	
    procFillGradientEllipseGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwFirst), Int64ToPtr(dwSecond), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), IntToPtr(int(angle)))
}
/*
*填充渐变路径
*dwFirst 开始颜色
*dwSecond  结束颜色
*rect 矩形区域
*angle 角度
*/
func (c *GdiPlusPaint)fillGradientPath(dwFirst int64, dwSecond int64, left float64, top float64, right float64, bottom float64, angle float64){
    procFillGradientPathGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwFirst), Int64ToPtr(dwSecond), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), IntToPtr(int(angle)))

}
/*
*绘制渐变的多边形
*dwFirst 开始颜色
*dwSecond  开始颜色
*strApt 点阵字符串 x1,y1 x2,y2...
*angle 角度
*/
func (c *GdiPlusPaint)fillGradientPolygon(dwFirst int64, dwSecond int64, strApt string, angle float64){	
    procFillGradientPolygonGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwFirst), Int64ToPtr(dwSecond), StringToUintPtr(strApt), IntToPtr(int(angle)))
}
/*
*绘制渐变矩形
*dwFirst 开始颜色
*dwSecond 开始颜色
*rect 矩形
*cornerRadius 边角半径
*angle 角度
*/
func (c *GdiPlusPaint)fillGradientRect(dwFirst int64, dwSecond int64, left float64, top float64, right float64, bottom float64, cornerRadius float64, angle float64){	
    procFillGradientRectGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwFirst), Int64ToPtr(dwSecond), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), IntToPtr(int(cornerRadius)), IntToPtr(int(angle)))
}
/*
*填充路径
*dwPenColor 颜色
*/
func (c *GdiPlusPaint)fillPath(dwPenColor int64){	
    procFillPathGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor))
}
/*
*绘制扇形
*dwPenColor 颜色
*rect 矩形区域
*startAngle 从x轴到弧线的起始点沿顺时针方向度量的角（以度为单位）
*sweepAngle 从startAngle参数到弧线的结束点沿顺时针方向度量的角（以度为单位）
*/
func (c *GdiPlusPaint)fillPie(dwPenColor int64, left float64, top float64, right float64, bottom float64, startAngle float64, sweepAngle float64){
    procFillPieGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), Float32ToPtr(float32(startAngle)), Float32ToPtr(float32(sweepAngle)))
}
/*
*填充多边形
*dwPenColor 颜色
*strApt 点阵字符串 x1,y1 x2,y2...
*/
func (c *GdiPlusPaint)fillPolygon(dwPenColor int64, strApt string){
    procFillPolygonGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), StringToUintPtr(strApt))
}
/*
*填充矩形
*dwPenColor 颜色
*left 左侧坐标
*top 顶部左标
*right 右侧坐标
*bottom 底部坐标
*/
func (c *GdiPlusPaint)fillRect(dwPenColor int64, left float64, top float64, right float64, bottom float64){	
    procFillRectGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))
}
/*
*填充圆角矩形
*dwPenColor 颜色
*rect 矩形区域
*cornerRadius 边角半径
*/
func (c *GdiPlusPaint)fillRoundRect(dwPenColor int64, left float64, top float64, right float64, bottom float64, cornerRadius float64){	
    procFillRoundRectGdiPlus.Call(IntToPtr(c.gID), Int64ToPtr(dwPenColor), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)), IntToPtr(int(cornerRadius)))
}
/*
*设置裁剪区域
*rect 区域
*/
func (c *GdiPlusPaint)setClip(left float64, top float64, right float64, bottom float64){
    procSetClipGdiPlus.Call(IntToPtr(c.gID), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))
}
/*
*设置直线两端的样式
*startLineCap 开始的样式
*endLineCap  结束的样式
*/
func (c *GdiPlusPaint)setLineCap(startLineCap int, endLineCap int){
    procSetLineCapGdiPlus.Call(IntToPtr(c.gID), IntToPtr(startLineCap), IntToPtr(endLineCap))
}
/*
*设置偏移
*mp 偏移坐标
*/
func (c *GdiPlusPaint)setOffset(offsetX float64, offsetY float64){
    procSetOffsetGdiPlus.Call(IntToPtr(c.gID), IntToPtr(int(offsetX)), IntToPtr(int(offsetY)))
}
/*
*设置透明度
*opacity 透明度
*/
func (c *GdiPlusPaint)setOpacity(opacity float64){
    procSetOpacityGdiPlus.Call(IntToPtr(c.gID), Float32ToPtr(float32(opacity)))
}
/*
*设置资源的路径
*resourcePath 资源的路径
*/
func (c *GdiPlusPaint)setResourcePath(resourcePath string){
    procSetResourcePathGdiPlus.Call(IntToPtr(c.gID), StringToUintPtr(resourcePath))
}
/*
*设置旋转角度
*rotateAngle 旋转角度
*/
func (c *GdiPlusPaint)setRotateAngle(rotateAngle float64){	
    procSetRotateAngleGdiPlus.Call(IntToPtr(c.gID), IntToPtr(int(rotateAngle)))
}
/*
*设置缩放因子
*scaleFactorX 横向因子
*scaleFactorY 纵向因子
*/
func (c *GdiPlusPaint)setScaleFactor(scaleFactorX float64, scaleFactorY float64){
    procSetScaleFactorGdiPlus.Call(IntToPtr(c.gID), FloatToPtr(scaleFactorX), FloatToPtr(scaleFactorY))
}
/*
*获取文字大小
*text 文字
*font 字体
*width 字符最大宽度
*data 返回数据 create_string_buffer(1024000) cx,cy
*/
func (c *GdiPlusPaint)textSize(strText string, font string, width float64)(string){	
    var bytes [1024]byte
	var cByte *byte = &bytes[0]
	ptr := uintptr(unsafe.Pointer(uintptr(unsafe.Pointer(cByte)) + uintptr(1)))
    procTextSizeGdiPlus2.Call(IntToPtr(c.gID), StringToUintPtr(strText), StringToUintPtr(font), IntToPtr(int(width)), ptr)
    return StringFromPtr(ptr)
}
/*
*消息循环
*hWnd 句柄
*message 消息ID
*/
func (c *GdiPlusPaint)onMessage(hWnd int, message int, wParam int, lParam int){	
    procOnMessage.Call(IntToPtr(c.gID), IntToPtr(hWnd), IntToPtr(message), IntToPtr(wParam), IntToPtr(lParam))
}
/*
*创建视图
*typeStr 类型
*name 名称
*/
func (c *GdiPlusPaint)createView(typeStr string, name string){	
    procCreateView.Call(IntToPtr(c.gID), StringToUintPtr(typeStr), StringToUintPtr(name))
}
/*
*设置属性
*name 名称
*atrName 属性名称
*atrValue 属性值
*/
func (c *GdiPlusPaint)setAttribute(name string, atrName string, atrValue string){
    procSetAttribute2.Call(IntToPtr(c.gID), StringToUintPtr(name), StringToUintPtr(atrName), StringToUintPtr(atrValue))
}
/*
*获取属性
*name 名称
*atrName 属性名称
*data 返回数据 create_string_buffer(1024000)
*/
func (c *GdiPlusPaint)getAttribute(name string, atrName string)(string){	
    var bytes [1024000]byte
	var cByte *byte = &bytes[0]
	ptr := uintptr(unsafe.Pointer(uintptr(unsafe.Pointer(cByte)) + uintptr(1)))
    procGetAttribute.Call(IntToPtr(c.gID), StringToUintPtr(name), StringToUintPtr(atrName), ptr)
    return StringFromPtr(ptr)
}
/*
*获取属性
*name 名称
*left 左侧坐标
*top 顶部左标
*right 右侧坐标
*bottom 底部坐标
*/
func (c *GdiPlusPaint)paintView(name string, left float64, top float64, right float64, bottom float64){	
    procPaintView.Call(IntToPtr(c.gID), StringToUintPtr(name), IntToPtr(int(left)), IntToPtr(int(top)), IntToPtr(int(right)), IntToPtr(int(bottom)))
}
/*
*设置焦点
*name 名称
*/
func (c *GdiPlusPaint)focusView(name string){	
    procFocusView.Call(IntToPtr(c.gID), StringToUintPtr(name))
}
/*
*设置焦点
*name 名称
*/
func (c *GdiPlusPaint)unFocusView(name string){	
    procUnFocusView.Call(IntToPtr(c.gID), StringToUintPtr(name))
}
/*
*鼠标按下视图
*name 名称
*x 横坐标
*y 纵坐标
*buttons 按钮
*clicks 点击次数
*/
func (c *GdiPlusPaint)mouseDownView(name string, x float64, y float64, buttons int, clicks int){	
    procMouseDownView.Call(IntToPtr(c.gID), StringToUintPtr(name), IntToPtr(int(x)), IntToPtr(int(y)), IntToPtr(buttons), IntToPtr(clicks))
}
/*
*鼠标抬起视图
*name 名称
*x 横坐标
*y 纵坐标
*buttons 按钮
*clicks 点击次数
*/
func (c *GdiPlusPaint)mouseUpView(name string, x float64, y float64, buttons int, clicks int){
    procMouseUpView.Call(IntToPtr(c.gID), StringToUintPtr(name), IntToPtr(int(x)), IntToPtr(int(y)), IntToPtr(buttons), IntToPtr(clicks))
}
/*
*鼠标移动视图
*name 名称
*x 横坐标
*y 纵坐标
*buttons 按钮
*clicks 点击次数
*/
func (c *GdiPlusPaint)mouseMoveView(name string, x float64, y float64, buttons int, clicks int){	
    procMouseMoveView.Call(IntToPtr(c.gID), StringToUintPtr(name), IntToPtr(int(x)), IntToPtr(int(y)), IntToPtr(buttons), IntToPtr(clicks))
}
/*
*鼠标滚动视图
*name 名称
*x 横坐标
*y 纵坐标
*buttons 按钮
*clicks 点击次数
*delta 滚动值
*/
func (c *GdiPlusPaint)mouseWheelView(name string, x float64, y float64, buttons int, clicks int, delta int){	
    procMouseWheelView.Call(IntToPtr(c.gID), StringToUintPtr(name), IntToPtr(int(x)), IntToPtr(int(y)), IntToPtr(buttons), IntToPtr(clicks), IntToPtr(delta))
}
/*
*鼠标滚动视图
*name 名称
*x 横坐标
*y 纵坐标
*buttons 按钮
*clicks 点击次数
*delta 滚动值
*/
func (c *GdiPlusPaint)setCursor(cursor string){	
    procSetCursor.Call(IntToPtr(c.gID), StringToUintPtr(cursor))
}
/*
*移除视图
*name 名称
*/
func (c *GdiPlusPaint)removeView(name string){	
    procRemoveView.Call(IntToPtr(c.gID), StringToUintPtr(name))
}
/*
*消息循环
*/
func (c *GdiPlusPaint)pumpMessage(){	
    procPumpMessage.Call()
}

/*
* 扩展接口
*/
type FCObject interface{
}

/*
* 基础视图
*/
type FCView struct {
    AllowDrag bool //是否允许拖动
    AllowResize bool //是否可以拖动改变大小
	Align string //横向布局
    AllowDragScroll bool //是否允许拖动滚动
    AllowPreviewsEvent bool //是否允许预处理事件
    BackColor string //背景色
    BackImage string
	BorderColor string //边线色
    BorderWidth float64 //边线宽度
    ClipRect FCRect //裁剪区域
    CornerRadius float64 //圆角
    Cursor string //光标
    DisplayOffset bool //是否显示偏移量
    Dock string //悬浮状态
    DownScrollHButton bool //是否按下横向滚动条
	DownScrollVButton bool //是否按下纵向滚动条
    Enabled bool //是否可用
    ExAttributes map[string]string
    ExView bool
    Font string //字体
    HoveredColor string //鼠标悬停时的颜色
    HoverScrollHButton bool //是否悬停横向滚动条
	HoverScrollVButton bool //是否悬停纵向滚动条
    HScrollIsVisible bool //横向滚动是否显示
    IsNotEmpty bool //是否不为空
    Location FCPoint //坐标
    Margin FCPadding //外边距
    MaximumSize FCSize //最大大小
    Padding FCPadding //内边距
    PaintList []*FCPaint  //绘图对象
    ParentList []*FCView //父视图
    PushedColor string //鼠标按下时的颜色
    ResizePoint int //调整尺寸的点
    ScrollV float64 //纵向滚动
	ScrollH float64 //横向滚动
	ScrollSize float64 //滚动条的大小
	ShowHScrollBar bool //是否显示横向滚动条
	ShowVScrollBar bool //是否显示横向滚动条
	ScrollBarColor string //滚动条的颜色
	ScrollBarHoveredColor string //滚动条悬停的颜色
    Size FCSize //大小
    Src string
    StartScrollH float64 //开始滚动的值
	StartScrollV float64 //结束滚动的值
	StartPoint FCPoint //起始点
    StartRect FCRect //移动开始时的视图矩形
    TabIndex int //Tab索引
    TabStop bool //是否支持Tab
    Text string //文字
	TextColor string //前景色
    TopMost bool //是否置顶
    VerticalAlign string //纵向布局
	ViewName string //名称
    Views []*FCView //子视图
    ViewType string //类型
	Visible bool //可见性
    VScrollIsVisible bool //纵向滚动是否显示
    Chart []*FCChart //图表
    Calendar []*FCCalendar //日历
    SplitDiv []*FCSplitLayoutDiv //分割布局
    LayoutDiv []*FCLayoutDiv //横竖布局
    CheckBox []*FCCheckBox //复选框
    RadioButton []*FCRadioButton //单选框
    TabView []*FCTabView //多页夹
    TabPage []*FCTabPage //多页夹的页
    Menu []*FCMenu //菜单
    MenuItem []*FCMenuItem //菜单项
    ComboBox []*FCComboBox //下拉列表
    Grid []*FCGrid //表格
    Tree []*FCTree //树
    ObjectList []FCObject //扩展接口
}

/*
* 初始化
*/
func CreateView(viewType string)(*FCView){
    view := new(FCView)
    view.BackColor = "rgb(255,255,255)" 
    view.BorderColor = "rgb(150,150,150)"
    view.BorderWidth = 1
    view.TextColor = "rgb(0,0,0)" 
    view.Visible = true 
    view.Enabled = true
    view.ScrollSize = 8 
    view.ScrollBarColor = "rgb(200,200,200)"
    view.ScrollBarHoveredColor = "rgb(42,138,195)"
    view.DisplayOffset = true 
    view.Dock = "none" 
    view.Font = "Default,12"
    view.HoveredColor = "none"
    view.PushedColor = "rgb(200,200,200)"
    view.Align = "left" 
    view.VerticalAlign = "top" 
    view.IsNotEmpty = true
    view.ViewType = viewType
    view.ResizePoint = -1
    view.ExAttributes = make(map[string]string)
    if viewType == "tabview"{
        tabView := CreateTabView()
        view.TabView = append(view.TabView, tabView)
    }else if viewType == "button"{
        view.HoveredColor =  "rgb(150,150,150)"
        view.PushedColor = "rgb(200,200,200)"
    }else if viewType == "label"{
        view.BorderColor = "none"
    }else if viewType == "tabpage"{
        tabPage := CreateTabPage()
        view.Visible = false
        view.TabPage = append(view.TabPage, tabPage)
    }else if viewType == "layout"{
        layout := CreateLayoutDiv()
        view.LayoutDiv = append(view.LayoutDiv, layout)
    }else if viewType == "checkbox"{
        checkBox := CreateCheckBox()
        view.CheckBox = append(view.CheckBox, checkBox)
    }else if viewType == "radiobutton"{
        radioButton := CreateRadioButton()
        view.RadioButton = append(view.RadioButton, radioButton)
    }else if viewType == "split"{
        split := CreateSplitLayoutDiv()
        view.SplitDiv = append(view.SplitDiv, split)
    }else if viewType == "grid"{
        view.ShowVScrollBar = true
        view.ShowHScrollBar = true
        grid := CreateGrid()
        view.Grid = append(view.Grid, grid)
    }else if viewType == "tree"{ 
        view.ShowVScrollBar = true
        view.ShowHScrollBar = true
        tree := CreateTree()
        view.Tree = append(view.Tree, tree)
    }else if viewType == "chart"{ 
        chart := CreateChart()
        view.Chart = append(view.Chart, chart)
    }else if viewType == "calendar"{
        calendar := CreateCalendar()
        view.Calendar = append(view.Calendar, calendar)
    }else if viewType == "menu"{
        menu := CreateMenu()
        view.MaximumSize = CreateSize(100, 300)
        view.Size = CreateSize(100, 100)
        view.ShowHScrollBar = true
        view.ShowVScrollBar = true
        view.Visible = false
        view.Menu = append(view.Menu, menu)
        layout := CreateLayoutDiv()
        view.LayoutDiv = append(view.LayoutDiv, layout)
        layout.LayoutStyle = "toptobottom"
    }else if viewType == "menuitem"{
        menuItem := CreateMenuItem()
        view.HoveredColor =  "rgb(150,150,150)"
        view.PushedColor = "rgb(100,100,100)"
        view.Size = CreateSize(100, 25)
        view.MenuItem = append(view.MenuItem, menuItem)
    }else if viewType == "combobox"{
        comboBox := CreateComboBox()
        view.ComboBox = append(view.ComboBox, comboBox)
    }
    return view
}

func (c *FCView)GetParent()(*FCView){
    length := len(c.ParentList)
    if length > 0{
        return c.ParentList[0]
    }else{
        noneView := new(FCView)
        noneView.IsNotEmpty = false
        return noneView
    }
}

func (c *FCView)SetParent(parent *FCView){
    var pList []*FCView
    c.ParentList = pList
    c.ParentList = append(c.ParentList, parent)
}

func (c *FCView)GetPaint()(*FCPaint){
    length := len(c.PaintList)
    if length > 0{
        return c.PaintList[0]
    }else{
        nonePaint := new(FCPaint)
        nonePaint.IsNotEmpty = false
        return nonePaint
    }
}

func (c *FCView)SetPaint(paint *FCPaint){
    var pList []*FCPaint
    c.PaintList = pList
    c.PaintList = append(c.PaintList, paint)
}

func (c *FCView)GetObject()(FCObject){
    length := len(c.ObjectList)
    if length > 0{
        return c.ObjectList[0]
    }else{
        noneObject := new(FCObject)
        return noneObject
    }
}

func (c *FCView)SetObject(object FCObject){
    var pList []FCObject
    c.ObjectList = pList
    c.ObjectList = append(c.ObjectList, object)
}

func (c *FCView)GetChart()(*FCChart){
    length := len(c.Chart)
    if length > 0{
        return c.Chart[0]
    }else{
        noneChart := new(FCChart)
        noneChart.IsNotEmpty = false
        return noneChart
    }
}

func (c *FCView)SetChart(chart *FCChart){
    var pList []*FCChart
    c.Chart = pList
    c.Chart = append(c.Chart, chart)
}

func (c *FCView)GetCalendar()(*FCCalendar){
    length := len(c.Calendar)
    if length > 0{
        return c.Calendar[0]
    }else{
        noneCalendar := new(FCCalendar)
        noneCalendar.IsNotEmpty = false
        return noneCalendar
    }
}

func (c *FCView)SetCalendar(calendar *FCCalendar){
    var pList []*FCCalendar
    c.Calendar = pList
    c.Calendar = append(c.Calendar, calendar)
}

func (c *FCView)GetSplitDiv()(*FCSplitLayoutDiv){
    length := len(c.SplitDiv)
    if length > 0{
        return c.SplitDiv[0]
    }else{
        noneSplit := new(FCSplitLayoutDiv)
        noneSplit.IsNotEmpty = false
        return noneSplit
    }
}

func (c *FCView)SetSplitDiv(split *FCSplitLayoutDiv){
    var pList []*FCSplitLayoutDiv
    c.SplitDiv = pList
    c.SplitDiv = append(c.SplitDiv, split)
}

func (c *FCView)GetLayoutDiv()(*FCLayoutDiv){
    length := len(c.LayoutDiv)
    if length > 0{
        return c.LayoutDiv[0]
    }else{
        noneLayout := new(FCLayoutDiv)
        noneLayout.IsNotEmpty = false
        return noneLayout
    }
}

func (c *FCView)SetLayoutDiv(layout *FCLayoutDiv){
    var pList []*FCLayoutDiv
    c.LayoutDiv = pList
    c.LayoutDiv = append(c.LayoutDiv, layout)
}

func (c *FCView)GetCheckBox()(*FCCheckBox){
    length := len(c.CheckBox)
    if length > 0{
        return c.CheckBox[0]
    }else{
        noneCheckBox := new(FCCheckBox)
        noneCheckBox.IsNotEmpty = false
        return noneCheckBox
    }
}

func (c *FCView)SetCheckBox(checkBox *FCCheckBox){
    var pList []*FCCheckBox
    c.CheckBox = pList
    c.CheckBox = append(c.CheckBox, checkBox)
}

func (c *FCView)GetRadioButton()(*FCRadioButton){
    length := len(c.RadioButton)
    if length > 0{
        return c.RadioButton[0]
    }else{
        noneRadioButton := new(FCRadioButton)
        noneRadioButton.IsNotEmpty = false
        return noneRadioButton
    }
}

func (c *FCView)SetRadioButton(radioButton *FCRadioButton){
    var pList []*FCRadioButton
    c.RadioButton = pList
    c.RadioButton = append(c.RadioButton, radioButton)
}

func (c *FCView)GetTabPage()(*FCTabPage){
    length := len(c.TabPage)
    if length > 0{
        return c.TabPage[0]
    }else{
        noneTabPage := new(FCTabPage)
        noneTabPage.IsNotEmpty = false
        return noneTabPage
    }
}

func (c *FCView)SetTabPage(tabPage *FCTabPage){
    var pList []*FCTabPage
    c.TabPage = pList
    c.TabPage = append(c.TabPage, tabPage)
}

func (c *FCView)GetTabView()(*FCTabView){
    length := len(c.TabView)
    if length > 0{
        return c.TabView[0]
    }else{
        noneTabView := new(FCTabView)
        noneTabView.IsNotEmpty = false
        return noneTabView
    }
}

func (c *FCView)SetTabView(tabView *FCTabView){
    var pList []*FCTabView
    c.TabView = pList
    c.TabView = append(c.TabView, tabView)
}

func (c *FCView)GetMenu()(*FCMenu){
    length := len(c.Menu)
    if length > 0{
        return c.Menu[0]
    }else{
        noneMenu := new(FCMenu)
        noneMenu.IsNotEmpty = false
        return noneMenu
    }
}

func (c *FCView)SetMenu(menu *FCMenu){
    var pList []*FCMenu
    c.Menu = pList
    c.Menu = append(c.Menu, menu)
}

func (c *FCView)GetMenuItem()(*FCMenuItem){
    length := len(c.MenuItem)
    if length > 0{
        return c.MenuItem[0]
    }else{
        noneMenuItem := new(FCMenuItem)
        noneMenuItem.IsNotEmpty = false
        return noneMenuItem
    }
}

func (c *FCView)SetMenuItem(menuItem *FCMenuItem){
    var pList []*FCMenuItem
    c.MenuItem = pList
    c.MenuItem = append(c.MenuItem, menuItem)
}

func (c *FCView)GetComboBox()(*FCComboBox){
    length := len(c.ComboBox)
    if length > 0{
        return c.ComboBox[0]
    }else{
        noneComboBox := new(FCComboBox)
        noneComboBox.IsNotEmpty = false
        return noneComboBox
    }
}

func (c *FCView)SetComboBox(comboBox *FCComboBox){
    var pList []*FCComboBox
    c.ComboBox = pList
    c.ComboBox = append(c.ComboBox, comboBox)
}

func (c *FCView)GetGrid()(*FCGrid){
    length := len(c.Grid)
    if length > 0{
        return c.Grid[0]
    }else{
        noneGrid := new(FCGrid)
        noneGrid.IsNotEmpty = false
        return noneGrid
    }
}

func (c *FCView)SetGrid(grid *FCGrid){
    var pList []*FCGrid
    c.Grid = pList
    c.Grid = append(c.Grid, grid)
}

func (c *FCView)GetTree()(*FCTree){
    length := len(c.Tree)
    if length > 0{
        return c.Tree[0]
    }else{
        noneTree := new(FCTree)
        noneTree.IsNotEmpty = false
        return noneTree
    }
}

func (c *FCView)SetTree(tree *FCTree){
    var pList []*FCTree
    c.Tree = pList
    c.Tree = append(c.Tree, tree)
}

/*
* 菜单
*/
type FCMenu struct{
    AutoSize bool //是否自动适应尺寸
    ComboBox []*FCView //所在的下拉菜单
    IsNotEmpty bool
    Items []*FCView //菜单项
    Popup bool //是否弹出
}

/*
* 创建菜单
*/
func CreateMenu()(*FCMenu){
    menu := new(FCMenu)
    menu.IsNotEmpty = true
    menu.AutoSize = true
    return menu
}

/*
* 菜单项
*/
type FCMenuItem struct{
    DropDownMenu []*FCView //下拉菜单
    IsNotEmpty bool
    Items []*FCView //菜单项
    ParentMenu []*FCView //所在菜单
    ParentItem []*FCView //父菜单项
    Value string //值
}

/*
* 创建菜单项
*/
func CreateMenuItem()(*FCMenuItem){
    menuItem := new(FCMenuItem)
    menuItem.IsNotEmpty = true
    return menuItem
}

func (c *FCMenu)GetComboBox()(*FCView){
    length := len(c.ComboBox)
    if length > 0{
        return c.ComboBox[0]
    }else{
        noneComboBox := new(FCView)
        noneComboBox.IsNotEmpty = false
        return noneComboBox
    }
}

func (c *FCMenu)SetComboBox(cb *FCView){
    var pList []*FCView
    c.ComboBox = pList
    c.ComboBox = append(c.ComboBox, cb)
}

func (c *FCMenuItem)GetDropDownMenu()(*FCView){
    length := len(c.DropDownMenu)
    if length > 0{
        return c.DropDownMenu[0]
    }else{
        noneMenu := new(FCView)
        noneMenu.IsNotEmpty = false
        return noneMenu
    }
}

func (c *FCMenuItem)SetDropDownMenu(m *FCView){
    var pList []*FCView
    c.DropDownMenu = pList
    c.DropDownMenu = append(c.DropDownMenu, m)
}

func (c *FCMenuItem)GetParentMenu()(*FCView){
    length := len(c.ParentMenu)
    if length > 0{
        return c.ParentMenu[0]
    }else{
        noneMenu := new(FCView)
        noneMenu.IsNotEmpty = false
        return noneMenu
    }
}

func (c *FCMenuItem)SetParentMenu(m *FCView){
    var pList []*FCView
    c.ParentMenu = pList
    c.ParentMenu = append(c.ParentMenu, m)
}

func (c *FCMenuItem)GetParentItem()(*FCView){
    length := len(c.ParentItem)
    if length > 0{
        return c.ParentItem[0]
    }else{
        noneItem := new(FCView)
        noneItem.IsNotEmpty = false
        return noneItem
    }
}

func (c *FCMenuItem)SetParentItem(m *FCView){
    var pList []*FCView
    c.ParentItem = pList
    c.ParentItem = append(c.ParentItem, m)
}

/*
* 下拉列表
*/
type FCComboBox struct{
    DropDownMenu []*FCView //下拉菜单
    IsNotEmpty bool
    SelectedIndex int
}

/*
* 创建下拉列表
*/
func CreateComboBox()(*FCComboBox){
    comboBox := new(FCComboBox)
    comboBox.IsNotEmpty = true
    comboBox.SelectedIndex = -1
    return comboBox
}

func (c *FCComboBox)GetDropDownMenu()(*FCView){
    length := len(c.DropDownMenu)
    if length > 0{
        return c.DropDownMenu[0]
    }else{
        noneMenu := new(FCView)
        noneMenu.IsNotEmpty = false
        return noneMenu
    }
}

func (c *FCComboBox)SetDropDownMenu(m *FCView){
    var pList []*FCView
    c.DropDownMenu = pList
    c.DropDownMenu = append(c.DropDownMenu, m)
}

/*
* 多页夹的页
*/
type FCTabPage struct{
    HeaderButton []*FCView //页头的按钮
    IsNotEmpty bool
}

/*
* 创建多页夹的页
*/
func CreateTabPage()(*FCTabPage){
    tabPage := new(FCTabPage)
    tabPage.IsNotEmpty = true
    return tabPage
}

func (c *FCTabPage)GetHeaderButton()(*FCView){
    length := len(c.HeaderButton)
    if length > 0{
        return c.HeaderButton[0]
    }else{
        noneView := new(FCView)
        noneView.IsNotEmpty = false
        return noneView
    }
}

func (c *FCTabPage)SetHeaderButton(view *FCView){
    var pList []*FCView
    c.HeaderButton = pList
    c.HeaderButton = append(c.HeaderButton, view)
}

/*
* 多页夹
*/
type FCTabView struct{
    AnimationSpeed int //动画速度
    IsNotEmpty bool
    Layout string //布局方式
    TabPages []*FCView //页夹集合
    UnderLineColor string //下划线的颜色
    UnderLineSize float64 //下划线的宽度
    UnderPoint FCPoint //下划点
    UseAnimation bool //是否使用动画
}

/*
* 创建多页夹的页
*/
func CreateTabView()(*FCTabView){
    tabView := new(FCTabView)
    tabView.IsNotEmpty = true
    tabView.Layout = "top" 
    tabView.UnderLineColor = "none" 
    tabView.AnimationSpeed = 20 
    return tabView
}

/*
* 复选按钮
*/
type FCCheckBox struct{
    ButtonSize FCSize //按钮的大小
    Checked bool //是否选中
    IsNotEmpty bool
}

/*
* 创建复选按钮
*/
func CreateCheckBox()(*FCCheckBox){
    checkBox := new(FCCheckBox)
    checkBox.IsNotEmpty = true
    checkBox.ButtonSize = CreateSize(16, 16)
    return checkBox
}

/*
* 单选按钮
*/
type FCRadioButton struct{
    ButtonSize FCSize //按钮的大小
    Checked bool //是否选中
    GroupName string //组别
    IsNotEmpty bool
}

/*
* 创建单选按钮
*/
func CreateRadioButton()(*FCRadioButton){
    radioButton := new(FCRadioButton)
    radioButton.IsNotEmpty = true
    radioButton.ButtonSize = CreateSize(16, 16)
    return radioButton
}

/*
* 横竖布局
*/
type FCLayoutDiv struct{
    AutoWrap bool //是否自动换行
    IsNotEmpty bool
    LayoutStyle string //分割方式
}

/*
* 创建横竖布局
*/
func CreateLayoutDiv()(*FCLayoutDiv){
    layout := new(FCLayoutDiv)
    layout.IsNotEmpty = true
    layout.LayoutStyle = "lefttoright" 
    return layout
}

/*
* 分割布局
*/
type FCSplitLayoutDiv struct{
    FirstView []*FCView //第一个视图
    IsNotEmpty bool
    LayoutStyle string //布局方式
    OldSize FCSize //上次的尺寸
    SplitMode string //分割模式 percentsize百分比或absolutesize绝对值
    SplitPercent float64 //分割百分比
    SecondView []*FCView //第二个视图
    Splitter []*FCView //分割线
}

/*
* 创建分割布局
*/
func CreateSplitLayoutDiv()(*FCSplitLayoutDiv){
    split := new(FCSplitLayoutDiv)
    split.IsNotEmpty = true
    split.SplitMode = "absolutesize"
    split.SplitPercent = -1 
    split.LayoutStyle = "lefttoright"
    return split
}

func (c *FCSplitLayoutDiv)GetFirstView()(*FCView){
    length := len(c.FirstView)
    if length > 0{
        return c.FirstView[0]
    }else{
        noneView := new(FCView)
        noneView.IsNotEmpty = false
        return noneView
    }
}

func (c *FCSplitLayoutDiv)SetFirstView(view *FCView){
    var pList []*FCView
    c.FirstView = pList
    c.FirstView = append(c.FirstView, view)
}

func (c *FCSplitLayoutDiv)GetSecondView()(*FCView){
    length := len(c.SecondView)
    if length > 0{
        return c.SecondView[0]
    }else{
        noneView := new(FCView)
        noneView.IsNotEmpty = false
        return noneView
    }
}

func (c *FCSplitLayoutDiv)SetSecondView(view *FCView){
    var pList []*FCView
    c.SecondView = pList
    c.SecondView = append(c.SecondView, view)
}

func (c *FCSplitLayoutDiv)GetSplitter()(*FCView){
    length := len(c.Splitter)
    if length > 0{
        return c.Splitter[0]
    }else{
        noneView := new(FCView)
        noneView.IsNotEmpty = false
        return noneView
    }
}

func (c *FCSplitLayoutDiv)SetSplitter(view *FCView){
    var pList []*FCView
    c.Splitter = pList
    c.Splitter = append(c.Splitter, view)
}

/*
* 表格列
*/
type FCGridColumn struct {
    AllowSort bool //是否允许排序
    AllowResize bool //是否允许改变大小
    BackColor string //背景色
    BorderColor string //边线颜色
    Bounds FCRect //区域
    CellAlign string //left:居左 center:居中 right:居右
	ColName string //名称
    ColType string //类型 string:字符串 double:浮点型 int:整型 bool: 布尔型
    Font string //字体
    Frozen bool //是否冻结
    Index int //索引
    IsNotEmpty bool
    Sort string //排序模式
    Text string //文字
    TextColor string //文字颜色
    Visible bool //是否可见
    Width float64 //宽度
    WidthStr string //宽度字符串 
}

/*
* 初始化
*/
func CreateGridColumn()(*FCGridColumn){
    col := new(FCGridColumn)
    col.Width = 120
    col.Font = "Default,14" 
    col.BackColor = "rgb(200,200,200)" 
    col.BorderColor = "rgb(150,150,150)" 
    col.TextColor = "rgb(50,50,50)" 
    col.Sort = "none"
    col.Visible = true 
    col.Index = -1 
    col.CellAlign = "left"
    col.AllowSort = true
    col.IsNotEmpty = true
    return col
}

/*
* 表格单元格
*/
type FCGridCell struct {
    BackColor string //背景色
    BorderColor string //边线色
    ColSpan int //列距
    Column []*FCGridColumn //所在列
    Digit int //保留小数的位数
    Font string //字体
    IsNotEmpty bool
    Row []*FCGridRow //所在行
    RowSpan int //行距
    TextColor string //前景色
    Value string //值
    View []*FCView //所在行
}

/*
* 初始化
*/
func CreateGridCell()(*FCGridCell){
    cell := new(FCGridCell)
    cell.BackColor = "rgb(255,255,255)"
    cell.BorderColor = "rgb(150,150,150)" 
    cell.TextColor = "rgb(0,0,0)" 
    cell.Font = "Default,14" 
    cell.ColSpan = 1
    cell.RowSpan = 1 
    cell.IsNotEmpty = true
    cell.Digit = -1
    return cell
}

func (c *FCGridCell)GetColumn()(*FCGridColumn){
    length := len(c.Column)
    if length > 0{
        return c.Column[0]
    }else{
        noneColumn := new(FCGridColumn)
        noneColumn.IsNotEmpty = false
        return noneColumn
    }
}

func (c *FCGridCell)SetColumn(col *FCGridColumn){
    var pList []*FCGridColumn
    c.Column = pList
    c.Column = append(c.Column, col)
}

func (c *FCGridCell)GetRow()(*FCGridRow){
    length := len(c.Row)
    if length > 0{
        return c.Row[0]
    }else{
        noneRow := new(FCGridRow)
        noneRow.IsNotEmpty = false
        return noneRow
    }
}

func (c *FCGridCell)SetRow(r *FCGridRow){
    var pList []*FCGridRow
    c.Row = pList
    c.Row = append(c.Row, r)
}

func (c *FCGridCell)GetView()(*FCView){
    length := len(c.View)
    if length > 0{
        return c.View[0]
    }else{
        noneView := new(FCView)
        noneView.IsNotEmpty = false
        return noneView
    }
}

func (c *FCGridCell)SetView(v *FCView){
    var pList []*FCView
    c.View = pList
    c.View = append(c.View, v)
}

/*
* 表格行
*/
type FCGridRow struct {
    Cells []*FCGridCell //单元格
    IsNotEmpty bool
    Index int //索引
	Selected bool //是否选中
    SortColIndex int //排序的列
    Visible bool //是否可见
}

/*
* 初始化
*/
func CreateGridRow()(*FCGridRow){
    row := new(FCGridRow)
    row.Visible = true 
    row.Index = -1
    row.IsNotEmpty = true
    return row
}

/*
* 表格
*/
type FCGrid struct{
    Columns []*FCGridColumn //所有的列
    HeaderHeight float64 //头部高度
    IsNotEmpty bool
    RowHeight float64 //行高
    Rows []*FCGridRow //包含的所有行
    SelectedRowColor string //选中行的颜色
}

/*
* 初始化表格
*/
func CreateGrid()(*FCGrid){
    grid := new(FCGrid)
    grid.IsNotEmpty = true
    grid.RowHeight = 30
    grid.HeaderHeight = 30
    grid.SelectedRowColor = "rgb(125,125,125)" 
    return grid
}

/*
* 树
*/
type FCTree struct{
    CheckBoxWidth float64 //复选框占用的宽度
    ChildNodes []*FCTreeNode //子节点
    CollapsedWidth float64 //折叠按钮占用的宽度
    HeaderHeight float64 //头部高度
    Indent float64 //缩进
    IsNotEmpty bool
    RowHeight float64 //行高
    ShowCheckBox bool //是否显示复选框
    Rows []*FCTreeRow //包含的所有行
    Columns []*FCTreeColumn //所有的列
}

/*
* 初始化树
*/
func CreateTree()(*FCTree){
    tree := new(FCTree)
    tree.IsNotEmpty = true
    tree.RowHeight = 30 
    tree.HeaderHeight = 0 
    tree.Indent = 20 
    tree.CheckBoxWidth = 25
    tree.CollapsedWidth = 25
    return tree
}

/*
* 树的列
*/
type FCTreeColumn struct {
    Bounds FCRect //区域
    Index int //索引
    IsNotEmpty bool
    Visible bool //是否可见
	Width float64 //宽度  
    WidthStr string //宽度字符串
}

/*
* 初始化
*/
func CreateTreeColumn()(*FCTreeColumn){
    col := new(FCTreeColumn)
    col.Width = 120 
    col.Visible = true 
    col.Index = -1 
    col.IsNotEmpty = true
    return col
}

/*
* 树的列
*/
type FCTreeRow struct {
    Cells []*FCTreeNode //单元格
    Index int //索引
    IsNotEmpty bool
	Selected bool //是否选中
    Visible bool //是否可见
}

/*
* 初始化
*/
func CreateTreeRow()(*FCTreeRow){
    row := new(FCTreeRow)
    row.Visible = true 
    row.Index = -1 
    row.IsNotEmpty = true
    return row
}

/*
* 树节点
*/
type FCTreeNode struct {
    AllowCollapsed bool //是否允许折叠
    BackColor string //背景色
    Checked bool //是否选中
    ChildNodes []*FCTreeNode //子节点
    Collapsed bool //是否折叠
    Column []*FCTreeColumn //所有的列
    Font string //字体
    Indent float64 //缩进
    IsNotEmpty bool
    ParentNode []*FCTreeNode
    Row []*FCTreeRow //包含的所有行
    TextColor string //前景色
	Value string //值 
}

/*
* 初始化
*/
func CreateTreeNode()(*FCTreeNode){
    node := new(FCTreeNode)
    node.BackColor = "rgb(255,255,255)" 
    node.TextColor = "rgb(0,0,0)" 
    node.Font = "Default,14" 
    node.AllowCollapsed = true 
    node.IsNotEmpty = true
    return node
}

func (c *FCTreeNode)GetColumn()(*FCTreeColumn){
    length := len(c.Column)
    if length > 0{
        return c.Column[0]
    }else{
        noneColumn := new(FCTreeColumn)
        noneColumn.IsNotEmpty = false
        return noneColumn
    }
}

func (c *FCTreeNode)SetColumn(col *FCTreeColumn){
    var pList []*FCTreeColumn
    c.Column = pList
    c.Column = append(c.Column, col)
}

func (c *FCTreeNode)GetRow()(*FCTreeRow){
    length := len(c.Row)
    if length > 0{
        return c.Row[0]
    }else{
        noneColumn := new(FCTreeRow)
        noneColumn.IsNotEmpty = false
        return noneColumn
    }
}

func (c *FCTreeNode)SetRow(r *FCTreeRow){
    var pList []*FCTreeRow
    c.Row = pList
    c.Row = append(c.Row, r)
}

func (c *FCTreeNode)GetParentNode()(*FCTreeNode){
    length := len(c.ParentNode)
    if length > 0{
        return c.ParentNode[0]
    }else{
        noneColumn := new(FCTreeNode)
        noneColumn.IsNotEmpty = false
        return noneColumn
    }
}

func (c *FCTreeNode)SetParentNode(node *FCTreeNode){
    var pList []*FCTreeNode
    c.ParentNode = pList
    c.ParentNode = append(c.ParentNode, node)
}

/*
* 证券数据结构
*/
type SecurityData struct {
	Amount float64 //成交额
    Close float64 //收盘价
    Date float64 //日期，为1970年到现在的秒
    High float64 //最高价
    Low float64 //最低价
    Open float64 //开盘价
    Volume float64 //成交额
}

/*
* 基础图形
*/
type BaseShape struct {
    Color string //颜色
    Color2 string //颜色2
    Datas []float64 //第一组数据
    Datas2 []float64 //第二组数据
	DivIndex int //所在层
    IsNotEmpty bool
    LeftOrRight bool //依附于左轴或右轴
    LineWidth float64 //线的宽度
    ShapeName string //名称
    ShapeType string //类型
    ShowHideDatas []float64 //控制显示隐藏的数据
    Style string //样式
    Text string //显示的文字
    Title string //第一个标题
    Title2 string //第二个标题
    Value float64 //显示文字的值
}

/*
* 初始化
*/
func CreateBaseShape()(*BaseShape){
    shape := new(BaseShape)
    shape.ShapeType = "line"
    shape.LineWidth = 1 
    shape.Color = "none" 
    shape.Color2 = "none" 
    shape.LeftOrRight = true 
    shape.IsNotEmpty = true
    return shape
}

/*
* 画线工具结构
*/
type FCPlot struct {
    Key1 float64 //第一个键
    Key2 float64 //第二个键
    Key3 float64 //第三个键
    IsNotEmpty bool
    LineColor string //线的颜色
    LineWidth float64 //线的宽度
    PointColor string //线的颜色
    PlotType string //线的类型
    StartKey1 float64 //移动前第一个键
    StartValue1 float64 //移动前第一个值
    StartKey2 float64 //移动前第二个键
    StartValue2 float64 //移动前第二个值
    StartKey3 float64 //移动前第三个键
    StartValue3 float64 //移动前第三个值
    Value1 float64 //第一个值
    Value2 float64 //第二个值
    Value3 float64 //第三个值
}

/*
* 初始化
*/
func CreatePlot()(*FCPlot){
    plot := new(FCPlot)
    plot.PlotType = "Line" 
    plot.LineColor = "rgb(0,0,0)"
    plot.PointColor = "rgba(0,0,0,120)" 
    plot.LineWidth = 1 
    plot.IsNotEmpty = true
    return plot
}

/*
* 图表
*/
type FCChart struct{
    AutoFillHScale bool //是否填充满X轴
    AllowDragChartDiv bool //是否允许拖拽图层
    CandleDistance float64 //蜡烛线的距离
    CandleMax float64 //蜡烛线的最大值
    CandleMin float64 //蜡烛线的最小值
    CandleMaxRight float64 //蜡烛线的右轴最大值
    CandleMinRight float64 //蜡烛线的右轴最小值
    CrossTipColor string //十字线标识的颜色
    CrossLineColor string //十字线的颜色
    CandleDigit int //图表层保留小数的位数
    CandleDivPercent float64 //图表层的占比
    CandlePaddingTop float64 //图表层的上边距
    CandlePaddingBottom float64 //图表层的下边距
    CrossStopIndex int //鼠标停留位置
    Cycle string //周期
    Data []*SecurityData //子节点
    DownColor string //下跌颜色
    FirstVisibleIndex int //起始可见的索引
    GridColor string //网格颜色
    HScalePixel float64 //蜡烛线的宽度
    HScaleHeight float64 //X轴的高度
    HScaleFormat string //X轴的格式化字符，例如YYYY-mm-dd HH:MM:SS
    HScaleTextDistance float64 //X轴的文字间隔
    IndMax float64 //指标层的最大值
    IndMin float64 //指标的最小值
    IndMax2 float64 //指标层2的最大值
    IndMin2 float64 //指标层2的最小值
    IndMaxRight float64 //指标层的右轴最大值
    IndMinRight float64 //指标层的右轴最小值
    IndMax2Right float64 //指标层2的右轴最大值
    IndMin2Right float64 //指标层2的右轴最小值
    IndDigit int //指标层保留小数的位数
    IndDigit2 int //指标层2保留小数的位数
    IndDivPercent float64 //指标层的占比
    IndDivPercent2 float64 //指标层2的占比
    IndPaddingTop float64 //指标层的上边距
    IndPaddingBottom float64 //指标层的下边距
    IndPaddingTop2 float64 //指标层2的上边距
    IndPaddingBottom2 float64 //指标层2的下边距
    IndicatorColors []string
    IsNotEmpty bool //是否不为空
    LeftVScaleWidth float64 //左轴宽度
    LastVisibleIndex int //结束可见的索引
    LastRecordIsVisible bool //最后记录是否可见
    LastVisibleKey float64 //最后可见的主键
    LastValidIndex int //最后有效数据索引
    LineWidthChart float64
    MainIndicator string //主图指标
    Magnitude int //成交量的比例
    OffsetX float64 //横向绘图偏移
    PlotPointSizeChart float64 //画线的选中点大小
    Plots []*FCPlot //画线
    RightVScaleWidth float64 //右轴宽度
    RightSpace float64 //右侧空间
    ScaleColor string //刻度的颜色
    ShowIndicator string //显示指标
    ShowCrossLine bool //是否显示十字线
    SelectPlotPoint int //选中画线的点
    StartMovePlot bool //选中画线
    SelectShape string //选中的图形
    SelectShapeEx string //选中的图形信息
    Shapes []*BaseShape //扩展图形
    SPlot []*FCPlot //选中的线条
    TargetOldX float64 //缩小时旧的位置1
	TargetOldX2 float64 //放大时旧的位置2
    TouchPosition FCPoint //鼠标坐标
    VolMax float64 //成交量层的最大值
    VolMin float64 //成交量层的最小值
    VolMaxRight float64 //成交量层的右轴最大值
    VolMinRight float64 //成交量层的右轴最小值
    VolDigit int //成交量层保留小数的位数
    VolDivPercent float64 //成交量层的占比
    VolPaddingTop float64 //成交量层的上边距
    VolPaddingBottom float64 //成交量层的下边距
    VScaleDistance float64 //纵轴的间隔
    VScaleType string //纵轴的类型 log10代表指数坐标
    UpColor string //上涨颜色
    KChart float64
    BChart float64
    OXChart float64
    OYChart float64
    RChart float64
    GridStepChart float64 //网格计算临时变量
    GridDigitChart int //网格计算临时变量
    //拖动滚动的缓存
    FirstIndexCacheChart int
    FirstTouchIndexCacheChart int
    FirstTouchPointCacheChart FCPoint
    LastIndexCacheChart int
    SecondTouchIndexCacheChart int
    SecondTouchPointCacheChart FCPoint
    FirstPaddingTop float64
    FirtstPaddingBottom float64
    TouchDownPointChart FCPoint
    AddingPlotChart string
    X4Chart float64
    Y4Chart float64
    NHighChart float64
    NLowChart float64
    XChart float64
    YChart float64
    WChart float64
    HChart float64
    UpSubValue float64
    DownSubValue float64
    Allema12 []float64
    Allema26 []float64
    Alldifarr []float64
    Alldeaarr []float64
    Allmacdarr []float64
    BollUp []float64
    BollDown []float64
    BollMid []float64
    Bias1 []float64
    Bias2 []float64
    Bias3 []float64
    KdjK []float64
    KdjD []float64
    KdjJ []float64
    Rsi1 []float64
    Rsi2 []float64
    Rsi3 []float64
    Roc []float64
    RocMa []float64
    Wr1 []float64
    Wr2 []float64
    Cci []float64
    Bbi []float64
    Trix []float64
    TrixMa []float64
    Dma1 []float64
    Dma2 []float64
    Ma5 []float64
    Ma10 []float64
    Ma20 []float64
    Ma30 []float64
    Ma120 []float64
    Ma250 []float64
    CloseArr []float64
}

/*
* 创建图表
*/
func CreateChart()(*FCChart){
    chart := new(FCChart)
    chart.IsNotEmpty = true
    chart.HScalePixel = 11
    chart.DownColor = "rgb(15,193,118)" 
    chart.LeftVScaleWidth = 80
    chart.UpColor = "rgb(219,68,83)" 
    chart.FirstVisibleIndex = -1 
    chart.LastVisibleIndex = -1
    chart.HScaleHeight = 30
    chart.ScaleColor = "rgb(255,0,0)"
    chart.CrossTipColor = "rgb(50,50,50)" 
    chart.CrossLineColor = "rgb(100,100,100)"
    chart.CandleDigit = 2 
    chart.IndDigit = 2 
    chart.IndDigit2 = 2 
    chart.LastRecordIsVisible = true
    chart.CandleDivPercent = 0.5 
    chart.VolDivPercent = 0.2 
    chart.IndDivPercent = 0.3 
    chart.GridColor = "rgba(255,0,0,120)" 
    chart.Magnitude = 1 
    chart.ShowCrossLine = false
    chart.CandlePaddingTop = 30
    chart.CandlePaddingBottom = 30 
    chart.VolPaddingTop = 20 
    chart.VolPaddingBottom = 0 
    chart.IndPaddingTop = 20
    chart.IndPaddingBottom = 20 
    chart.IndPaddingTop2 = 20 
    chart.IndPaddingBottom2 = 20
    chart.VScaleDistance = 35
    chart.VScaleType = "standard" 
    chart.SelectPlotPoint =-1 
    chart.CrossStopIndex =-1 
    chart.Cycle = "second" 
    chart.LastValidIndex =-1 
    chart.HScaleTextDistance = 10 
    chart.LineWidthChart = 1
    chart.PlotPointSizeChart = 20 
    chart.FirstIndexCacheChart =-1
    chart.FirstTouchIndexCacheChart =-1
    chart.LastIndexCacheChart =-1
    chart.SecondTouchIndexCacheChart =-1
    var indicatorColors[]string
	indicatorColors = append(indicatorColors, "rgb(100,100,100)")
	indicatorColors = append(indicatorColors, "rgb(206,147,27)")
	indicatorColors = append(indicatorColors, "rgb(150,0,150)")
	indicatorColors = append(indicatorColors, "rgb(255,0,0)")
	indicatorColors = append(indicatorColors, "rgb(0,150,150)")
	indicatorColors = append(indicatorColors, "rgb(0,150,0)")
	indicatorColors = append(indicatorColors, "rgb(59,174,218)")
	indicatorColors = append(indicatorColors, "rgb(50,50,50)")
    chart.IndicatorColors = indicatorColors
    return chart
}

func (c *FCChart)GetSelectedPlot()(*FCPlot){
    length := len(c.SPlot)
    if length > 0{
        return c.SPlot[0]
    }else{
        nonePlot := new(FCPlot)
        nonePlot.IsNotEmpty = false
        return nonePlot
    }
}

func (c *FCChart)SetSelectedPlot(plot *FCPlot){
    var pList []*FCPlot
    c.SPlot = pList
    c.SPlot = append(c.SPlot, plot)
}

/*
* 日历
*/
type FCCalendar struct{
    DayDiv []*DayDiv //日层
    HeadDiv []*HeadDiv //头部层
    IsNotEmpty bool //是否不为空
    Mode string //模式
    MonthDiv []*MonthDiv //月层
    SelectedDay []*CDay //选中日
    TimeDiv []*TimeDiv //时间层
    UseAnimation bool //是否使用动画
    YearDiv []*YearDiv //年层
    Years map[int]*CYear //日历
}

/*
* 创建日历
*/
func CreateCalendar()(*FCCalendar){
    calendar := new(FCCalendar)
    calendar.IsNotEmpty = true
    calendar.Mode = "day"
    calendar.Years = make(map[int]*CYear)
    calendar.IsNotEmpty = true
    return calendar
}

/*
* 月层
*/
type MonthDiv struct {
    ADirection int //动画的方向
    ATick int //动画当前帧数
    ATotalTick int //动画总帧数
    IsNotEmpty bool
    Month int //月份
    MonthButtons []*MonthButton //月的按钮
    MonthButtonsAm []*MonthButton //动画日期的集合
    Year int //年份  
}

/*
* 初始化
*/
func CreateMonthDiv()(*MonthDiv){
    monthDiv := new(MonthDiv)
    monthDiv.IsNotEmpty = true
    monthDiv.ATotalTick = 40
    return monthDiv
}

/*
* 年层
*/
type YearDiv struct {
    ADirection int //动画的方向
    ATick int //动画当前帧数
    ATotalTick int //动画总帧数
    IsNotEmpty bool
    StartYear int //开始年份
    YearButtons []*YearButton //年的按钮
    YearButtonsAm []*YearButton //动画日期的集合
}

/*
* 初始化
*/
func CreateYearDiv()(*YearDiv){
    yearDiv := new(YearDiv)
    yearDiv.IsNotEmpty = true
    yearDiv.ATotalTick = 40
    return yearDiv
}

/*
* 头部层
*/
type HeadDiv struct {
    ArrowColor string //箭头颜色
    BackColor string //箭头颜色
    Bounds FCRect //显示区域
    IsNotEmpty bool
    TextColor string //文字颜色
    TitleFont string //标题字体
    WeekFont string //星期字体
}

/*
* 初始化
*/
func CreateHeadDiv()(*HeadDiv){
    headDiv := new(HeadDiv)
    headDiv.IsNotEmpty = true
    headDiv.TitleFont = "Default,20" 
    headDiv.WeekFont = "Default,14" 
    headDiv.ArrowColor = "rgb(150,150,150)"
    headDiv.BackColor = "rgb(255,255,255)"
    headDiv.TextColor = "rgb(0,0,0)" 
    return headDiv
}

/*
* 时间层
*/
type TimeDiv struct {
    Bounds FCRect //显示区域
    IsNotEmpty bool
}

/*
* 初始化
*/
func CreateTimeDiv()(*TimeDiv){
    timeDiv := new(TimeDiv)
    timeDiv.IsNotEmpty = true
    return timeDiv
}

/*
* 头部层
*/
type CYear struct {
    IsNotEmpty bool
    Months map[int]*CMonth
    Year int //年
}

/*
* 初始化
*/
func CreateCYear()(*CYear){
    cYear := new(CYear)
    cYear.IsNotEmpty = true
    cYear.Months = make(map[int]*CMonth)
    return cYear
}

/*
* 月的结构
*/
type CMonth struct {
    Days map[int]*CDay
    IsNotEmpty bool
    Month int //月
    Year int //年
}

/*
* 初始化
*/
func CreateCMonth()(*CMonth){
    cMonth := new(CMonth)
    cMonth.IsNotEmpty = true
    cMonth.Days = make(map[int]*CDay)
    return cMonth
}

/*
* 日的结构
*/
type CDay struct {
    Day int //日
    IsNotEmpty bool
    Month int //月
    Year int //年
}

/*
* 初始化
*/
func CreateCDay()(*CDay){
    cDay := new(CDay)
    cDay.IsNotEmpty = true
    return cDay
}

func (c *FCCalendar)GetDayDiv()(*DayDiv){
    length := len(c.DayDiv)
    if length > 0{
        return c.DayDiv[0]
    }else{
        noneDayDiv := new(DayDiv)
        noneDayDiv.IsNotEmpty = false
        return noneDayDiv
    }
}

func (c *FCCalendar)SetDayDiv(d *DayDiv){
    var pList []*DayDiv
    c.DayDiv = pList
    c.DayDiv = append(c.DayDiv, d)
}

func (c *FCCalendar)GetHeadDiv()(*HeadDiv){
    length := len(c.HeadDiv)
    if length > 0{
        return c.HeadDiv[0]
    }else{
        noneHeadDiv := new(HeadDiv)
        noneHeadDiv.IsNotEmpty = false
        return noneHeadDiv
    }
}

func (c *FCCalendar)SetHeadDiv(h *HeadDiv){
    var pList []*HeadDiv
    c.HeadDiv = pList
    c.HeadDiv = append(c.HeadDiv, h)
}

func (c *FCCalendar)GetMonthDiv()(*MonthDiv){
    length := len(c.MonthDiv)
    if length > 0{
        return c.MonthDiv[0]
    }else{
        noneMonthDiv := new(MonthDiv)
        noneMonthDiv.IsNotEmpty = false
        return noneMonthDiv
    }
}

func (c *FCCalendar)SetMonthDiv(m *MonthDiv){
    var pList []*MonthDiv
    c.MonthDiv = pList
    c.MonthDiv = append(c.MonthDiv, m)
}

func (c *FCCalendar)GetYearDiv()(*YearDiv){
    length := len(c.YearDiv)
    if length > 0{
        return c.YearDiv[0]
    }else{
        noneYearDiv := new(YearDiv)
        noneYearDiv.IsNotEmpty = false
        return noneYearDiv
    }
}

func (c *FCCalendar)SetYearDiv(y *YearDiv){
    var pList []*YearDiv
    c.YearDiv = pList
    c.YearDiv = append(c.YearDiv, y)
}

func (c *FCCalendar)GetTimeDiv()(*TimeDiv){
    length := len(c.TimeDiv)
    if length > 0{
        return c.TimeDiv[0]
    }else{
        noneTimeDiv := new(TimeDiv)
        noneTimeDiv.IsNotEmpty = false
        return noneTimeDiv
    }
}

func (c *FCCalendar)SetTimeDiv(t *TimeDiv){
    var pList []*TimeDiv
    c.TimeDiv = pList
    c.TimeDiv = append(c.TimeDiv, t)
}

func (c *FCCalendar)GetSelectedDay()(*CDay){
    length := len(c.SelectedDay)
    if length > 0{
        return c.SelectedDay[0]
    }else{
        noneDay := new(CDay)
        noneDay.IsNotEmpty = false
        return noneDay
    }
}

func (c *FCCalendar)SetSelectedDay(d *CDay){
    var pList []*CDay
    c.SelectedDay = pList
    c.SelectedDay = append(c.SelectedDay, d)
}

/*
* 日的按钮
*/
type DayButton struct {
    BackColor string //背景颜色
    BorderColor string //文字颜色
    Bounds FCRect //显示区域
    CDay []*CDay
    Font string //字体
    InThisMonth bool //是否在本月
    IsNotEmpty bool
    Selected bool //是否被选中
    TextColor string //文字颜色
    TextColor2 string //第二个文字颜色
    Visible bool //是否可见
}

/*
* 初始化
*/
func CreateDayButton()(*DayButton){
    dayButton := new(DayButton)
    dayButton.IsNotEmpty = true
    dayButton.Visible = true 
    dayButton.Font = "Default,16" 
    dayButton.TextColor = "rgb(0,0,0)" 
    dayButton.BackColor = "none" 
    dayButton.TextColor2 = "rgb(50,50,50)" 
    dayButton.BorderColor = "rgb(150,150,150)" 
    return dayButton
}

func (c *DayButton)GetDay()(*CDay){
    length := len(c.CDay)
    if length > 0{
        return c.CDay[0]
    }else{
        noneDay := new(CDay)
        noneDay.IsNotEmpty = false
        return noneDay
    }
}

func (c *DayButton)SetDay(d *CDay){
    var pList []*CDay
    c.CDay = pList
    c.CDay = append(c.CDay, d)
}

/*
* 月的按钮
*/
type MonthButton struct {
    BackColor string //背景颜色
    BorderColor string //文字颜色
    Bounds FCRect //显示区域
    Font string //字体
    IsNotEmpty bool
    Month int //月
    Selected bool //是否被选中
    TextColor string //文字颜色
    Visible bool //是否可见
    Year int //年 
}

/*
* 初始化
*/
func CreateMonthButton()(*MonthButton){
    monthButton := new(MonthButton)
    monthButton.IsNotEmpty = true
    monthButton.Visible = true 
    monthButton.Font = "Default,16" 
    monthButton.TextColor = "rgb(0,0,0)" 
    monthButton.BackColor = "none" 
    monthButton.BorderColor = "rgb(150,150,150)" 
    return monthButton
}

/*
* 年的按钮
*/
type YearButton struct {
    BackColor string //背景颜色
    BorderColor string //文字颜色
    Bounds FCRect //显示区域
    Font string //字体
    IsNotEmpty bool
    Selected bool //是否被选中
    TextColor string //文字颜色
    Visible bool //是否可见
    Year int //年
}

/*
* 初始化
*/
func CreateYearButton()(*YearButton){
    yearButton := new(YearButton)
    yearButton.IsNotEmpty = true
    yearButton.Visible = true 
    yearButton.Font = "Default,16" 
    yearButton.TextColor = "rgb(0,0,0)" 
    yearButton.BackColor = "none" 
    yearButton.BorderColor = "rgb(150,150,150)"
    return yearButton
}

/*
* 日期层
*/
type DayDiv struct {
     AClickRowFrom int //点击时的上月的行
     AClickRowTo int //点击时的当月的行
     ADirection int //动画的方向
     ATick int //动画当前帧数
     ATotalTick int //动画总帧数
     DayButtons []*DayButton //日期的集合
     DayButtonsAm []*DayButton //动画日期的集合
     IsNotEmpty bool
}

/*
* 初始化
*/
func CreateDayDiv()(*DayDiv){
    dayDiv := new(DayDiv)
    dayDiv.IsNotEmpty = true
    dayDiv.ATotalTick = 40 
    return dayDiv
}

/*
* 数字转换成字符串，指定保留位数
*/
func ToFixed(value float64, digit int)(string){
    return strconv.FormatFloat(value, 'f', digit, 64)
}

/*
* 添加顶层视图
* view 视图
* paint 绘图对象
*/
func AddView(view *FCView, paint *FCPaint) {
    view.SetPaint(paint)
    paint.Views = append(paint.Views, view)
}

/*
* 添加到父视图
* view 视图
* parent 父视图
*/
func AddViewToParent(view *FCView, parent *FCView) {
    view.SetPaint(parent.GetPaint())
    parent.Views = append(parent.Views, view)
    view.SetParent(parent)
}

/*
* 插入到顶层视图
* view 视图
* paint 绘图对象
* index 索引
*/
func InsertView(view *FCView, paint *FCPaint, index int) {
    view.SetPaint(paint)
    newViews := paint.Views[:index]
    newViews = append(newViews, view)
    newViews = append(newViews, paint.Views[index:]...)
    paint.Views = newViews
}

/*
* 插入到到父视图
* view 视图
* parent 父视图
* index 索引
*/
func InsertViewToParent(view *FCView, parent *FCView, index int) {
    view.SetPaint(parent.GetPaint())
    newViews := parent.Views[:index]
    newViews = append(newViews, view)
    newViews = append(newViews, parent.Views[index:]...)
    parent.Views = newViews
    view.SetParent(parent)
}

/*
* 清除视图
*paint 绘图对象
*/
func ClearViews(paint *FCPaint){
    ClearViewInputs(paint.Views)
    var views []*FCView
    paint.Views = views
}

/*
* 清除输入框
* views:视图集合
*/
func ClearViewInputs(views []*FCView) {
    if len(views) > 0{
        for i := 0; i < len(views); i++ {
            view := views[i]
            if view.ExView{
                view.GetPaint().GdiPlus.removeView(view.ViewName)
                view.ExView = false
            }
        }
    }
}

/*
* 移除顶层视图
* view 视图
* paint 绘图对象
*/
func RemoveView(view *FCView, paint *FCPaint) {
    if len(paint.Views) > 0 {
        for i := 0; i < len(paint.Views); i++ {
            if paint.Views[i] == view {
                paint.Views = append(paint.Views[:i], paint.Views[i + 1:]...)
                if view.ExView{
                    var removeViews []*FCView
                    removeViews = append(removeViews, view)
                    ClearViewInputs(removeViews)
                }
                break
            }
        }
    }
}

/*
* 从父视图中移除
* view 视图
* parent 父视图
*/
func RemoveViewFromParent(view *FCView, parent *FCView) {
    if len(parent.Views) > 0 {
        for i := 0; i < len(parent.Views); i++ {
            if parent.Views[i] == view {
                parent.Views = append(parent.Views[:i], parent.Views[i + 1:]...)
                if view.ExView{
                    var removeViews []*FCView
                    removeViews = append(removeViews, view)
                    ClearViewInputs(removeViews)
                }
                break
            }
        }
    }
}

/*
* 获取绝对位置X
* view:视图
*/
func ClientX(view *FCView)(float64) {
    if view.IsNotEmpty {
        cLeft := view.Location.X
        pView := view.GetParent()
        if pView.IsNotEmpty {
            if pView.DisplayOffset && pView.ScrollH != 0 {
                return cLeft + ClientX(pView) - pView.ScrollH
            } else {
                return cLeft + ClientX(pView)
            }
        } else {
            return cLeft
        }
    } else {
        return 0
    }
}

/*
* 获取绝对位置Y
* view:视图
*/
func ClientY(view *FCView)(float64) {
    if view.IsNotEmpty {
      cTop := view.Location.Y
      pView := view.GetParent()
      if pView.IsNotEmpty {
          if pView.DisplayOffset && pView.ScrollV != 0 {
            return cTop + ClientY(pView) - pView.ScrollV
          } else {
            return cTop + ClientY(pView)
          }
      } else {
          return cTop
      }
  } else {
      return 0
  }
}

/*
* 是否包含坐标
* view:视图
* mp:坐标
*/
func ContainsPoint(view *FCView, mp FCPoint)(bool){
    if IsViewEnabled(view){
        clx := ClientX(view)
        cly := ClientY(view)
        size := view.Size
        cp := CreatePoint(mp.X - clx, mp.Y - cly)
        if cp.X >= 0 && cp.X <= size.Cx &&
            cp.Y >= 0 && cp.Y <= size.Cy {
            return true
        } else {
            return false
        }
    }else{
        return false
    }
}

/*
* 根据名称查找视图
* name:名称
* views:视图集合
*/
func FindViewByName(name string, views []*FCView)(*FCView) {
    size := len(views)
    if(size > 0){
        for i := 0; i < size; i++ {
            view := views[i]
            if view.ViewName == name {
                return view
            } else {
                if len(view.Views) > 0 {
                    subView := FindViewByName(name, view.Views)
                    if subView.IsNotEmpty {
                        return subView
                    }
                }
            }
        }
    }
    noneView := new(FCView)
    noneView.IsNotEmpty = false
	return noneView
}

/*
* 根据坐标查找视图
* mp:坐标
* views:视图集合
*/
func FindView(mp FCPoint, views []*FCView)(*FCView) {
    size := len(views)
    if size > 0{
        for i := 0; i < size; i++ {
            view := views[size - i - 1]
            if view.Visible && view.TopMost {
                hasPoint := false
                paint := view.GetPaint()
                if(paint.OnContainsPoint != nil){
                    hasPoint = paint.OnContainsPoint(view, mp)
                }else{
                    hasPoint = ContainsPoint(view, mp)
                }
                if hasPoint {
                    if view.VScrollIsVisible {
                        clx := ClientX(view)
                        if mp.X >= clx + view.Size.Cx - view.ScrollSize {
                            return view
                        }
                    }
                    if view.HScrollIsVisible {
                        cly := ClientY(view)
                        if mp.Y >= cly + view.Size.Cy - view.ScrollSize {
                            return view
                        }
                    }
                    if len(view.Views) > 0 {
                        subView := FindView(mp, view.Views)
                        if subView.IsNotEmpty {
                            return subView
                        }
                    }
                    return view
                }
            }
        }
        for i := 0; i < size; i++ {
            view := views[size - i - 1]
            if view.Visible && !view.TopMost {
                hasPoint := false
                paint := view.GetPaint()
                if(paint.OnContainsPoint != nil){
                    hasPoint = paint.OnContainsPoint(view, mp)
                }else{
                    hasPoint = ContainsPoint(view, mp)
                }
                if hasPoint {
                    if view.VScrollIsVisible {
                        clx := ClientX(view)
                        if mp.X >= clx + view.Size.Cx - view.ScrollSize {
                            return view
                        }
                    }
                    if (view.HScrollIsVisible) {
                        cly := ClientY(view)
                        if mp.Y >= cly + view.Size.Cy - view.ScrollSize {
                            return view
                        }
                    }
                    if len(view.Views) > 0 {
                        subView := FindView(mp, view.Views)
                        if subView.IsNotEmpty {
                            return subView
                        }
                    }
                    return view
                }
            }
        }
    }
    noneView := new(FCView)
    noneView.IsNotEmpty = false
	return noneView
}

/*
* 是否重绘时可见
* view:视图
*/
func IsPaintVisible(view *FCView)(bool) {
    if view.Visible {
        pView := view.GetParent()
        if pView.IsNotEmpty {
            if pView.Visible {
                return IsPaintVisible(pView)
            } else {
                return false
            }
        } else {
            return true
        }
    } else {
        return false
    }
}

/*
* 是否可用
* view:视图
*/
func IsViewEnabled(view *FCView)(bool) {
    if view.Enabled {
        pView := view.GetParent()
        if pView.IsNotEmpty {
            if pView.Enabled {
                return IsViewEnabled(pView)
            } else {
                return false
            }
        } else {
            return true
        }
    } else {
        return false
    }
}

/*
* 获取区域的交集
*/
func GetIntersectRect(lpDestRect *FCRect, lpSrc1Rect FCRect, lpSrc2Rect FCRect)(int){
    lpDestRect.Left = math.Max(lpSrc1Rect.Left, lpSrc2Rect.Left)
    lpDestRect.Right = math.Min(lpSrc1Rect.Right, lpSrc2Rect.Right)
    lpDestRect.Top = math.Max(lpSrc1Rect.Top, lpSrc2Rect.Top)
    lpDestRect.Bottom = math.Min(lpSrc1Rect.Bottom, lpSrc2Rect.Bottom)
    if lpDestRect.Right > lpDestRect.Left && lpDestRect.Bottom > lpDestRect.Top {
        return 1
    }else {
        lpDestRect.Left = 0
        lpDestRect.Right = 0
        lpDestRect.Top = 0
        lpDestRect.Bottom = 0
        return 0
    }
}

/*
* 全局刷新方法
* paint:绘图对象
*/
func Invalidate(paint *FCPaint) {
    if(paint.OnInvalidate != nil){
        paint.OnInvalidate(paint)
    }else{
        hDC := GetDCW32(paint.HWnd)
	    paint.HDC = hDC
        noneRect := CreateRect(0, 0, 0, 0)
        noneRect.IsNotEmpty = false
	    drawRect := CreateRect(0, 0, (paint.Size.Cx / paint.ScaleFactorX), (paint.Size.Cy / paint.ScaleFactorY))
        allRect := CreateRect(0, 0, paint.Size.Cx, paint.Size.Cy)
        paint.GdiPlus.setScaleFactor(paint.ScaleFactorX, paint.ScaleFactorY)
	    paint.BeginPaint(allRect, drawRect)
        if(paint.OnRenderViews != nil){
            paint.OnRenderViews(paint.Views, paint, drawRect)
        }else{
	        RenderViews(paint.Views, paint, drawRect)
        }
	    paint.EndPaint()
	    ReleaseDCW32(paint.HWnd, hDC)
    }
}

/*
* 刷新视图方法
* view:视图
*/
func InvalidateView(view *FCView) {
    paint := view.GetPaint()
    if paint.AllowPartialPaint{
        if(paint.OnInvalidateView != nil){
            paint.OnInvalidateView(view)
        }else{
            if(IsPaintVisible(view)){  
                hDC := GetDCW32(paint.HWnd)
                paint.HDC = hDC
                clX := ClientX(view)
                clY := ClientY(view)
                drawRect := CreateRect(clX, clY, clX + view.Size.Cx, clY + view.Size.Cy)
                drawViews := paint.Views
                allRect := CreateRect(0, 0, paint.Size.Cx, paint.Size.Cy)
                paint.GdiPlus.setScaleFactor(paint.ScaleFactorX, paint.ScaleFactorY)
                paint.BeginPaint(allRect, drawRect)
                if(paint.OnRenderViews != nil){
                    paint.OnRenderViews(drawViews, paint, drawRect)
                }else{
                    RenderViews(drawViews, paint, drawRect)
                }
                paint.EndPaint()
                ReleaseDCW32(paint.HWnd, hDC)
            }
        }
    }else{
        Invalidate(paint)
    }
}

/*
* 更新悬浮状态
* views:视图集合
*/
func UpdateViewDefault(views []*FCView) {
    if len(views) > 0{
        for i := 0; i < len(views); i++ {
            view := views[i]
            pView := view.GetParent()
            leftStr, ok := view.ExAttributes["leftstr"]
            if ok{
                pWidth := view.GetPaint().Size.Cx / view.GetPaint().ScaleFactorX
                if (pView.IsNotEmpty){
                    pWidth = pView.Size.Cx
                }
                leftStr = strings.Replace(leftStr, "%", "", -1)
                view.Location.X = ConvertToFloat64(leftStr) * pWidth / 100
            }
            topStr, ok2 := view.ExAttributes["topstr"]
            if ok2{
                pHeight := view.GetPaint().Size.Cy / view.GetPaint().ScaleFactorY
                if (pView.IsNotEmpty){
                    pHeight = pView.Size.Cy
                }
                topStr = strings.Replace(topStr, "%", "", -1)
                view.Location.Y = ConvertToFloat64(topStr) * pHeight / 100
            }
            widthStr, ok3 := view.ExAttributes["widthstr"]
            if ok3{
                pWidth := view.GetPaint().Size.Cx / view.GetPaint().ScaleFactorX
                if (pView.IsNotEmpty){
                    pWidth = pView.Size.Cx
                }
                widthStr = strings.Replace(widthStr, "%", "", -1)
                view.Size.Cx = ConvertToFloat64(widthStr) * pWidth / 100
            }
            heightStr, ok4 := view.ExAttributes["heightstr"]
            if ok4{
                pHeight := view.GetPaint().Size.Cy / view.GetPaint().ScaleFactorY
                if (pView.IsNotEmpty){
                    pHeight = pView.Size.Cy
                }
                heightStr = strings.Replace(heightStr, "%", "", -1)
                view.Size.Cy = ConvertToFloat64(heightStr) * pHeight / 100
            }
            if pView.IsNotEmpty && pView.ViewType != "split" {
                margin := view.Margin
			    padding := pView.Padding
                if view.Dock == "fill" {
                    view.Location = CreatePoint(margin.Left + padding.Left, margin.Top + padding.Top)
                    vcx := pView.Size.Cx - margin.Left - padding.Left - margin.Right - padding.Right
                    if vcx < 0{
                        vcx = 0
                    }
                    vcy := pView.Size.Cy - margin.Top - padding.Top - margin.Bottom - padding.Bottom
                    if vcy < 0{
                        vcy = 0
                    }
                    view.Size = CreateSize(vcx, vcy)
                } else if view.Dock == "left" {
                    view.Location = CreatePoint(margin.Left + padding.Left, margin.Top + padding.Top)
                    vcy := pView.Size.Cy - margin.Top - padding.Top - margin.Bottom - padding.Bottom
                    if vcy < 0{
                        vcy = 0
                    }
                    view.Size = CreateSize(view.Size.Cx, vcy)
                } else if view.Dock == "top" {
                    view.Location = CreatePoint(margin.Left + padding.Left, margin.Top + padding.Top)
                    vcx := pView.Size.Cx - margin.Left - padding.Left - margin.Right - padding.Right
                    if vcx < 0{
                        vcx = 0
                    }
                    view.Size = CreateSize(vcx, view.Size.Cy)
                } else if view.Dock == "right" {
                    view.Location = CreatePoint(pView.Size.Cx - view.Size.Cx - padding.Right - margin.Right, margin.Top + padding.Top)
                    vcy := pView.Size.Cy - margin.Top - padding.Top - margin.Bottom - padding.Bottom
                    if vcy < 0{
                        vcy = 0
                    }
                    view.Size = CreateSize(view.Size.Cx, vcy)
                } else if view.Dock == "bottom" {
                    view.Location = CreatePoint(margin.Left + padding.Left, pView.Size.Cy - view.Size.Cy - margin.Bottom - padding.Bottom)
                    vcx := pView.Size.Cx - margin.Left - padding.Left - margin.Right - padding.Right
                    if vcx < 0{
                        vcx = 0
                    }
                    view.Size = CreateSize(vcx, view.Size.Cy)
                }
                if view.Align == "center" {
                    view.Location = CreatePoint((pView.Size.Cx - view.Size.Cx) / 2, view.Location.Y)
                }else if view.Align == "right"{
                    view.Location = CreatePoint(pView.Size.Cx - view.Size.Cx - padding.Right - margin.Right, view.Location.Y)
                }
                if view.VerticalAlign == "middle" {
                    view.Location = CreatePoint(view.Location.X, (pView.Size.Cy - view.Size.Cy) / 2)
                }else if view.VerticalAlign == "bottom"{
                    view.Location = CreatePoint(view.Location.X, pView.Size.Cy - view.Size.Cy - padding.Bottom - margin.Bottom)
                }
            }else if !pView.IsNotEmpty{
                if view.Dock == "fill"{
				    view.Size = CreateSize(view.GetPaint().Size.Cx / view.GetPaint().ScaleFactorX, view.GetPaint().Size.Cy / view.GetPaint().ScaleFactorY)
                }
            }
            if view.ViewType == "split" {
                ResetSplitLayoutDiv(view)
            } else if view.ViewType == "tabview"{
                UpdateTabLayout(view)
            } else if view.ViewType == "layout" {
                ResetLayoutDiv(view)
            } else if view.ViewType == "calendar" {
                UpdateCalendar(view)
            } else if view.ViewType == "chart"{
                chart := view          
                ResetChartVisibleRecord(chart)
                CheckChartLastVisibleIndex(chart)
                if chart.GetPaint().OnCalculateMaxMin != nil{
                    chart.GetPaint().OnCalculateMaxMin(chart)
                }else{
                    CalculateChartMaxMin(chart)
                }
            }
            if len(view.Views) > 0 {
                UpdateViewDefault(view.Views)
            }
        }
    }
}

/*
* 视图尺寸改变
*/
func WindowResize(oldRect FCRect, resizePoint int, nowPoint FCPoint, startTouchPoint FCPoint)(FCRect){
    rect := CreateRect(oldRect.Left, oldRect.Top, oldRect.Right, oldRect.Bottom)
	if resizePoint == 0{
		rect.Left = rect.Left + nowPoint.X - startTouchPoint.X;
		rect.Top = rect.Top + nowPoint.Y - startTouchPoint.Y;
	}else if resizePoint == 1{
		rect.Left = rect.Left + nowPoint.X - startTouchPoint.X;
		rect.Bottom = rect.Bottom + nowPoint.Y - startTouchPoint.Y;
	}else if resizePoint == 2{
		rect.Right = rect.Right + nowPoint.X - startTouchPoint.X;
		rect.Top = rect.Top + nowPoint.Y - startTouchPoint.Y;
	}else if resizePoint == 3{
		rect.Right = rect.Right + nowPoint.X - startTouchPoint.X;
		rect.Bottom = rect.Bottom + nowPoint.Y - startTouchPoint.Y;
	}else if resizePoint == 4{
		rect.Left = rect.Left + nowPoint.X - startTouchPoint.X;
	}else if resizePoint == 5{
		rect.Top = rect.Top + nowPoint.Y - startTouchPoint.Y;
	}else if resizePoint == 6{
		rect.Right = rect.Right + nowPoint.X - startTouchPoint.X;
	}else if resizePoint == 7{
		rect.Bottom = rect.Bottom + nowPoint.Y - startTouchPoint.Y;
	}
    return rect;
}

/*
* 获取调整尺寸的点
*/
func GetResizeState(view *FCView, mp FCPoint)(int){
	bWidth := 5.0;
	width := view.Size.Cx;
    height := view.Size.Cy;
	if (mp.X >= 0 && mp.X <= bWidth * 2 && mp.Y >= 0 && mp.Y <= bWidth * 2){
		return 0;
	}else if (mp.X >= 0 && mp.X <= bWidth * 2 && mp.Y >= height - bWidth * 2 && mp.Y <= height){
		return 1;
	}else if (mp.X >= width - bWidth * 2 && mp.X <= width && mp.Y >= 0 && mp.Y <= bWidth * 2){
		return 2;
	}else if (mp.X >= width - bWidth * 2 && mp.X <= width && mp.Y >= height - bWidth * 2 && mp.Y <= height){
		return 3;
	}else if (mp.X >= 0 && mp.X <= bWidth && mp.Y >= 0 && mp.Y <= height){
		return 4;
	}else if (mp.X >= 0 && mp.X <= width && mp.Y >= 0 && mp.Y <= bWidth){
		return 5;
	}else if (mp.X >= width - bWidth && mp.X <= width && mp.Y >= 0 && mp.Y <= height){
		return 6;
	}else if (mp.X >= 0 && mp.X <= width && mp.Y >= height - bWidth && mp.Y <= height){
		return 7;
	}else{
		return -1;
	}
}

/*
* 重绘复选按钮
* checkBox:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawCheckBox(checkBox *FCView, paint *FCPaint, clipRect FCRect){
    inCheckBox := checkBox.GetCheckBox()
    width := checkBox.Size.Cx
    height := checkBox.Size.Cy
    if checkBox.TextColor != "none" {
        eRight := inCheckBox.ButtonSize.Cx + 10
        eRect := CreateRect(1, (height - inCheckBox.ButtonSize.Cy) / 2, inCheckBox.ButtonSize.Cx + 1, (height + inCheckBox.ButtonSize.Cy) / 2)
        if len(checkBox.Text) == 0{
            eRect = CreateRect((width - inCheckBox.ButtonSize.Cx) / 2, (height - inCheckBox.ButtonSize.Cy) / 2, (width + inCheckBox.ButtonSize.Cx) / 2, (height + inCheckBox.ButtonSize.Cy) / 2)
        }
        paint.DrawRect(checkBox.TextColor, 1, 0, eRect.Left, eRect.Top, eRect.Right, eRect.Bottom)
        if inCheckBox.Checked {
            eRect.Left += 2
            eRect.Top += 2
            eRect.Right -= 2
            eRect.Bottom -= 2
            var drawPoints []FCPoint
		    drawPoints = append(drawPoints, CreatePoint(eRect.Left, eRect.Top + 8))
		    drawPoints = append(drawPoints, CreatePoint(eRect.Left + 6, eRect.Bottom))
		    drawPoints = append(drawPoints, CreatePoint(eRect.Right - 1, eRect.Top))
		    paint.DrawPolyline(checkBox.TextColor, 1, 0, drawPoints)
        }
        if len(checkBox.Text) > 0{
            tSize := paint.TextSize(checkBox.Text, checkBox.Font)
            paint.DrawText(checkBox.Text, checkBox.TextColor, checkBox.Font, eRight, (height - tSize.Cy) / 2)
        }
    }
}

/*
* 重绘单选按钮
* radioButton:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawRadioButton(radioButton *FCView, paint *FCPaint, clipRect FCRect) {
    inRadioButton := radioButton.GetRadioButton()
    height := radioButton.Size.Cy
    if radioButton.TextColor != "none" {
        eRight := inRadioButton.ButtonSize.Cx + 10
        eRect := CreateRect(1, (height - inRadioButton.ButtonSize.Cy) / 2, inRadioButton.ButtonSize.Cx + 1, (height + inRadioButton.ButtonSize.Cy) / 2)
        paint.DrawEllipse(radioButton.TextColor, 1, 0, eRect.Left, eRect.Top, eRect.Right, eRect.Bottom)
        if inRadioButton.Checked {
            eRect.Left += 2
            eRect.Top += 2
            eRect.Right -= 3
            eRect.Bottom -= 3
            paint.FillEllipse(radioButton.TextColor, eRect.Left, eRect.Top, eRect.Right, eRect.Bottom)
        }
        tSize := paint.TextSize(radioButton.Text, radioButton.Font)
        paint.DrawText(radioButton.Text, radioButton.TextColor, radioButton.Font, eRight, (height - tSize.Cy) / 2)
    }
}

/*
* 重绘按钮
* button:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawButton(button *FCView, paint *FCPaint, clipRect FCRect) {
    if button == paint.GetTouchDownView() {
        if button.PushedColor != "none" {
            paint.FillRoundRect(button.PushedColor, 0, 0, button.Size.Cx, button.Size.Cy, button.CornerRadius)
        } else if button.BackColor != "none" {
            paint.FillRoundRect(button.BackColor, 0, 0, button.Size.Cx, button.Size.Cy, button.CornerRadius)
        }
    } else if button == paint.GetTouchMoveView() {
        if button.HoveredColor != "none" {
            paint.FillRoundRect(button.HoveredColor, 0, 0, button.Size.Cx, button.Size.Cy, button.CornerRadius)
        } else if button.BackColor != "none" {
            paint.FillRoundRect(button.BackColor, 0, 0, button.Size.Cx, button.Size.Cy, button.CornerRadius)
        }
    } else if button.BackColor != "none"{
        paint.FillRoundRect(button.BackColor, 0, 0, button.Size.Cx, button.Size.Cy, button.CornerRadius)
    }
    if button.TextColor != "none" && len(button.Text) > 0 {
        tSize := paint.TextSize(button.Text, button.Font)
        paint.DrawText(button.Text, button.TextColor, button.Font, (button.Size.Cx - tSize.Cx) / 2, (button.Size.Cy - tSize.Cy) / 2)
    }
    if button.BorderColor != "none" {
        paint.DrawRoundRect(button.BorderColor, button.BorderWidth, 0, 0, 0, button.Size.Cx, button.Size.Cy, button.CornerRadius)
    }
}

/*
* 点击复选按钮
* checkBox:视图
* mp:坐标
*/
func ClickCheckBox(checkBox *FCView, mp FCPoint) {
    inCheckBox := checkBox.GetCheckBox()
    inCheckBox.Checked = !inCheckBox.Checked
}

/*
* 点击单选按钮
* radioButton:视图
* mp: 坐标
*/
func ClickRadioButton(radioButton *FCView, mp FCPoint) {
    inRadioButton := radioButton.GetRadioButton()
    if radioButton.GetParent().IsNotEmpty && len(radioButton.GetParent().Views) > 0 {
        for i := 0; i < len(radioButton.GetParent().Views); i++ {
            rView := radioButton.GetParent().Views[i]
            if rView.ViewType == "radiobutton"{
                rButton := rView
                if rView != radioButton &&
                        rButton.GetRadioButton().GroupName == inRadioButton.GroupName {
                    rButton.GetRadioButton().Checked = false
                }
            }
        }
    }
    inRadioButton.Checked = true
}

/*
* 获取月的日数
* year:年
* month:月
*/
func GetDaysInMonth(year int, month int)(int) {
    switch month {
        case 1:
            return 31
        case 3:
            return 31
        case 5:
            return 31
        case 7:
            return 31
        case 8:
            return 31
        case 10:
            return 31
        case 12:
            return 31
        case 4:
            return 30
        case 6:
            return 30
        case 9:
            return 30
        case 11:
            return 30
        case 2:
            if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0){
                    return 29
            }else{
                    return 28
            }
    default:
        return 0
    }
}

/*
* 根据字符获取月份
* month:月
*/
func GetMonthStr(month int)(string){
    switch month {
        case 1:
            return "一月"
        case 2:
            return "二月"
        case 3:
            return "三月"
        case 4:
            return "四月"
        case 5:
            return "五月"
        case 6:
            return "六月"
        case 7:
            return "七月"
        case 8:
            return "八月"
        case 9:
            return "九月"
        case 10:
            return "十月"
        case 11:
            return "十一月"
        case 12:
            return "十二月"
        default:
            return ""
    }
}

/*
* 获取年
* years:年的集合
* year:年
*/
func GetYear(calendar *FCView, year int)(*CYear){
    inCalendar := calendar.GetCalendar()
    cy := CreateCYear()
    cy.IsNotEmpty = false
    _, ok := inCalendar.Years[year]
    if ok {
        cy = inCalendar.Years[year]
    }else {
        cy.IsNotEmpty = true
        cy.Year = year
        inCalendar.Years[year] = cy
        for i := 1; i <= 12; i++ {
            cMonth := CreateCMonth()
            cMonth.Year = year
            cMonth.Month = i
            daysInMonth := GetDaysInMonth(year, i)
            for j := 1; j <= daysInMonth; j++ {
                cDay := CreateCDay()
                cDay.Year = year
                cDay.Month = i
                cDay.Day = j
                cMonth.Days[j] = cDay
            }
            cy.Months[i] = cMonth
        } 
    }
    return cy
}

/*
* 显示隐藏日期层
* dayDiv:日期层
* visible:是否可见
*/
func ShowOrHideDayDiv(dayDiv *DayDiv, visible bool) {
    dayButtonSize := len(dayDiv.DayButtons)
    for i := 0; i < dayButtonSize; i++ {
        dayButton := dayDiv.DayButtons[i]
        dayButton.Visible = visible
    }
}

/*
* 显示隐藏月层
* monthDiv:月层
* visible:是否可见
*/
func ShowOrHideMonthDiv(monthDiv *MonthDiv, visible bool) {
    monthButtonSize := len(monthDiv.MonthButtons)
    for i := 0; i < monthButtonSize; i++ {
        monthButton := monthDiv.MonthButtons[i]
        monthButton.Visible = visible
    }
}

/*
* 显示隐藏年层
* yearButtons:年层
* visible:是否可见
*/
func ShowOrHideYearDiv(yearDiv *YearDiv, visible bool) {
    yearButtonSize := len(yearDiv.YearButtons)
    for i := 0; i < yearButtonSize; i++ {
        yearButton := yearDiv.YearButtons[i]
        yearButton.Visible = visible
    }
}

/*
* 初始化日历
* calendar:日历
*/
func InitCalendar(calendar *FCView) {
    inCalendar := calendar.GetCalendar()
    dayDiv := CreateDayDiv()
    monthDiv := CreateMonthDiv()
    yearDiv := CreateYearDiv()
    headDiv := CreateHeadDiv()
    timeDiv := CreateTimeDiv()
    inCalendar.SetDayDiv(dayDiv)
    inCalendar.SetMonthDiv(monthDiv)
    inCalendar.SetYearDiv(yearDiv)
    inCalendar.SetHeadDiv(headDiv)
    inCalendar.SetTimeDiv(timeDiv)
    
    for i := 0; i < 42; i++ {
        dayButton := CreateDayButton()
        dayDiv.DayButtons = append(dayDiv.DayButtons, dayButton)
        dayFCButtonm := CreateDayButton()
        dayFCButtonm.Visible = false
        dayDiv.DayButtonsAm = append(dayDiv.DayButtonsAm, dayFCButtonm)
    }
    for i := 0; i < 42; i++ {
        monthButton := CreateMonthButton()
        monthButton.Month = (i + 1)
        monthDiv.MonthButtons = append(monthDiv.MonthButtons, monthButton)
        monthButtonAm := CreateMonthButton()
        monthButtonAm.Visible = false
        monthButtonAm.Month = (i + 1)
        monthDiv.MonthButtonsAm = append(monthDiv.MonthButtonsAm, monthButtonAm)
    }
    for i := 0; i < 42; i++ {
        yearButton := CreateYearButton()
        yearDiv.YearButtons = append(yearDiv.YearButtons, yearButton)
        yearButtonAm := CreateYearButton()
        yearButtonAm.Visible = false
        yearDiv.YearButtonsAm = append(yearDiv.YearButtonsAm, yearButtonAm)
    }
}

/*
* 获取星期
* y:年
* m:月
* d:日
*/
func DayOfWeek(y int, m int, d int)(int) {
    mm := m
    yy := y
    if mm == 1 || mm == 2 {
       mm += 12
       yy -= 1
   }
   return int(((d + 2 * mm + 3 * (mm + 1) / 5 + yy + yy / 4 - yy / 100 + yy / 400) + 1) % 7)
}

/*
* 获取当月
* calendar:日历
*/
func GetMonth(calendar *FCView)(*CMonth) {
    inCalendar := calendar.GetCalendar()
    cYear := GetYear(calendar, inCalendar.GetSelectedDay().Year)
    cMonth := cYear.Months[inCalendar.GetSelectedDay().Month]
    return cMonth
}

/*
* 获取下个月
* calendar:日历
* year:年
* month:月
*/
func GetNextMonth(calendar *FCView, year int, month int)(*CMonth) {
    nextMonth := month + 1
    nextYear := year
    if nextMonth == 13 {
      nextMonth = 1
      nextYear += 1
    }
    return GetYear(calendar, nextYear).Months[nextMonth]
}

/*
* 获取上个月
* calendar:日历
* year:年
* month:月
*/
func GetLastMonth(calendar *FCView, year int, month int)(*CMonth) {
    lastMonth := month - 1
    lastYear := year
    if lastMonth == 0 {
        lastMonth = 12
        lastYear -= 1
    }
    return GetYear(calendar, lastYear).Months[lastMonth]
}

/*
* 重置日期层布局
* calendar:日历
* dayDiv:日期层
* state:状态
*/
func ResetDayDiv(calendar *FCView, dayDiv *DayDiv, state int) {
    inCalendar := calendar.GetCalendar()
    thisMonth := GetMonth(calendar)
    lastMonth := GetLastMonth(calendar, thisMonth.Year, thisMonth.Month)
    nextMonth := GetNextMonth(calendar, thisMonth.Year, thisMonth.Month)
    left := 0.0
    headHeight := inCalendar.GetHeadDiv().Bounds.Bottom
    top := headHeight
    width := calendar.Size.Cx
    height := calendar.Size.Cy
    height -= inCalendar.GetTimeDiv().Bounds.Bottom - inCalendar.GetTimeDiv().Bounds.Top
    dayButtonHeight := height - headHeight
    if dayButtonHeight < 1 {
        dayButtonHeight = 1
    }
    toY := 0.0
    if dayDiv.ADirection == 1 {
        toY = dayButtonHeight * float64(dayDiv.ATick) / float64(dayDiv.ATotalTick)
        if state == 1 {
            thisMonth = nextMonth
            month := thisMonth.Month
            lastMonth = GetLastMonth(calendar, thisMonth.Year, month)
            nextMonth = GetNextMonth(calendar, thisMonth.Year, month)
        }
    }else if dayDiv.ADirection == 2 {
        toY = -dayButtonHeight * float64(dayDiv.ATick) / float64(dayDiv.ATotalTick)
        if state == 1 {
            thisMonth = lastMonth
            month := thisMonth.Month
            lastMonth = GetLastMonth(calendar, thisMonth.Year, month)
            nextMonth = GetNextMonth(calendar, thisMonth.Year, month)
        }
    }
    buttonSize := 0
    if state == 0 {
        buttonSize = len(dayDiv.DayButtons)
    } else if (state == 1) {
        buttonSize = len(dayDiv.DayButtonsAm)
    }
    dheight := dayButtonHeight / 6
    days := thisMonth.Days
    firstDay := days[1]
    startDayOfWeek := DayOfWeek(firstDay.Year, firstDay.Month, firstDay.Day)
    for i := 0; i < buttonSize; i++ {
        dayButton := new(DayButton)
        if state == 0 {
            dayButton = dayDiv.DayButtons[i]
            buttonSize = len(dayDiv.DayButtons)
        }else if state == 1 {
            dayButton = dayDiv.DayButtonsAm[i]
            buttonSize = len(dayDiv.DayButtonsAm)
        }
        if i == 35 {
            dheight = height - top
        }
        vOffset := 0.0
        if state == 1 {
            if dayDiv.ATick > 0 {
                dayButton.Visible = true
                if dayDiv.ADirection == 1 {
                    vOffset = toY - dayButtonHeight
                } else if dayDiv.ADirection == 2 {
                    vOffset = toY + dayButtonHeight

                }
            }else {
                dayButton.Visible = false
                continue
            }
        }else {
            vOffset = toY
        }
        if (i + 1) % 7 == 0 {
            dp := CreatePoint(left, top + vOffset)
            ds := CreateSize(width - left, dheight)
            bounds := CreateRect(dp.X, dp.Y, dp.X + ds.Cx, dp.Y + ds.Cy)
            dayButton.Bounds = bounds
            left = 0
            if i != 0 && i != buttonSize - 1 {
                top += dheight
            }
        }else {
            dp := CreatePoint(left, top + vOffset)
            ds := CreateSize(width / 7, dheight)
            //let ds = FCSize(cx:width / 7 + Double(((i + 1) % 7) % 2), cy:dheight)
            bounds := CreateRect(dp.X, dp.Y, dp.X + ds.Cx, dp.Y + ds.Cy)
            dayButton.Bounds = bounds
            left += ds.Cx
        }
        cDay := new(CDay)
        dayButton.InThisMonth = false
        if i >= startDayOfWeek && i <= startDayOfWeek + len(days) - 1 {
            cDay = days[i - startDayOfWeek + 1]
            dayButton.InThisMonth = true
        }else if i < startDayOfWeek {
            cDay = lastMonth.Days[len(lastMonth.Days) - startDayOfWeek + i + 1]
        }else if i > startDayOfWeek + len(days) - 1 {
            cDay = nextMonth.Days[i - startDayOfWeek - len(days) + 1]
        }
        dayButton.SetDay(cDay)
        if state == 0 && dayButton.GetDay().IsNotEmpty && dayButton.GetDay() == inCalendar.GetSelectedDay() {
            dayButton.Selected = true
        }else {
            dayButton.Selected = false
        }
    }
}

/*
* 重置月层布局
* calendar:日历
* monthDiv:月层
* state:状态
*/
func ResetMonthDiv(calendar *FCView, monthDiv *MonthDiv, state int) {
    inCalendar := calendar.GetCalendar()
    thisYear := monthDiv.Year
    lastYear := monthDiv.Year - 1
    nextYear := monthDiv.Year + 1
    left := 0.0
    headHeight := inCalendar.GetHeadDiv().Bounds.Bottom
    top := headHeight
    width := calendar.Size.Cx
    height := calendar.Size.Cy
    height -= inCalendar.GetTimeDiv().Bounds.Bottom - inCalendar.GetTimeDiv().Bounds.Top
    monthButtonHeight := height - top
    if monthButtonHeight < 1 {
        monthButtonHeight = 1
    }
    toY := 0.0
    var monthButtons []*MonthButton
    if monthDiv.ADirection == 1 {
        toY = monthButtonHeight * float64(monthDiv.ATick) / float64(monthDiv.ATotalTick)
        if state == 1 {
            thisYear = nextYear
            lastYear = thisYear - 1
            nextYear = thisYear + 1
        }
    }else if monthDiv.ADirection == 2 {
        toY = -monthButtonHeight * float64(monthDiv.ATick) / float64(monthDiv.ATotalTick)
        if state == 1 {
            thisYear = lastYear
            lastYear = thisYear - 1
            nextYear = thisYear + 1
        }
    }
    if state == 0 {
        monthButtons = monthDiv.MonthButtons
    }else if state == 1 {
        monthButtons = monthDiv.MonthButtonsAm
    }
    dheight := monthButtonHeight / 3
    buttonSize := len(monthButtons)
    for i := 0; i < buttonSize; i++ {
        if i == 8 {
            dheight = height - top
        }
        monthButton := monthButtons[i]
        monthButton.Year = thisYear
        vOffSet := 0.0
        if state == 1 {
            if monthDiv.ATick > 0{
                monthButton.Visible = true
                if monthDiv.ADirection == 1 {
                    vOffSet = toY - monthButtonHeight
                }else if monthDiv.ADirection == 2 {
                    vOffSet = toY + monthButtonHeight
                }
            }else {
                monthButton.Visible = false
                continue
            }
        }else {
            vOffSet = toY
        }
        if (i + 1) % 4 == 0 {
            dp := CreatePoint(left, top + vOffSet)
            ds := CreateSize(width - left, dheight)
            bounds := CreateRect(dp.X, dp.Y, dp.X + ds.Cx, dp.Y + ds.Cy)
            monthButton.Bounds = bounds
            left = 0
            if i != 0 && i != buttonSize - 1 {
                top += dheight
            }
        } else {
            dp := CreatePoint(left, top + vOffSet)
            //let ds = FCSize(width / 4 + ((i + 1) % 4) % 2, dheight)
            ds := CreateSize(width / 4, dheight)
            bounds := CreateRect(dp.X, dp.Y, dp.X + ds.Cx, dp.Y + ds.Cy)
            monthButton.Bounds = bounds
            left += ds.Cx
        }
    }
}

/*
* 重置年层布局
* calendar:日历
* yearDiv:年层
* state:状态
*/
func ResetYearDiv(calendar *FCView, yearDiv *YearDiv, state int) {
    inCalendar := calendar.GetCalendar()
    thisStartYear := yearDiv.StartYear
    lastStartYear := yearDiv.StartYear - 12
    nextStartYear := yearDiv.StartYear + 12
    left := 0.0
    headHeight := inCalendar.GetHeadDiv().Bounds.Bottom
    top := headHeight
    width := calendar.Size.Cx
    height := calendar.Size.Cy
    height -= inCalendar.GetTimeDiv().Bounds.Bottom - inCalendar.GetTimeDiv().Bounds.Top
    yearButtonHeight := height - top
    if yearButtonHeight < 1 {
        yearButtonHeight = 1
    }
    toY := 0.0
    var yearButtons []*YearButton
    if yearDiv.ADirection == 1 {
        toY = yearButtonHeight * float64(yearDiv.ATick) / float64(yearDiv.ATotalTick)
        if state == 1 {
            thisStartYear = nextStartYear
            lastStartYear = thisStartYear - 12
            nextStartYear = thisStartYear + 12
        }
    }else if yearDiv.ADirection == 2 {
        toY = -yearButtonHeight * float64(yearDiv.ATick) / float64(yearDiv.ATotalTick)
        if state == 1 {
            thisStartYear = lastStartYear
            lastStartYear = thisStartYear - 12
            nextStartYear = thisStartYear + 12
        }
    }
    if state == 0 {
        yearButtons = yearDiv.YearButtons
    }else if state == 1 {
        yearButtons = yearDiv.YearButtonsAm
    }
    dheight := yearButtonHeight / 3
    buttonSize := len(yearDiv.YearButtons)
    for i := 0; i < buttonSize; i++ {
        if i == 8 {
            dheight = height - top
        }
        yearButton := yearButtons[i]
        yearButton.Year = thisStartYear + i
        vOffSet := 0.0
        if state == 1 {
            if yearDiv.ATick > 0 {
                yearButton.Visible = true
                if yearDiv.ADirection == 1 {
                    vOffSet = toY - yearButtonHeight
                }else if yearDiv.ADirection == 2 {
                    vOffSet = toY + yearButtonHeight
                }
            }else {
                yearButton.Visible = false
                continue
            }
        }else {
            vOffSet = toY
        }
        if (i + 1) % 4 == 0 {
            dp := CreatePoint(left, top + vOffSet)
            ds := CreateSize(width - left, dheight)
            bounds := CreateRect(dp.X, dp.Y, dp.X + ds.Cx, dp.Y + ds.Cy)
            yearButton.Bounds = bounds
            left = 0
            if i != 0 && i != buttonSize - 1 {
                top += dheight
            }
        }else {
            dp := CreatePoint(left, top + vOffSet)
            //let ds = FCSize(width / 4 + ((i + 1) % 4) % 2, dheight)
            ds := CreateSize(width / 4, dheight)
            bounds := CreateRect(dp.X, dp.Y, dp.X + ds.Cx, dp.Y + ds.Cy)
            yearButton.Bounds = bounds
            left += ds.Cx
        }
    }
}

/*
* 选择开始年份
* calendar:日历
* yearDiv:年层
* startYear:开始年
*/
func SelectStartYear(calendar *FCView, yearDiv *YearDiv, startYear int) {
    inCalendar := calendar.GetCalendar()
    if yearDiv.StartYear != startYear {
        if startYear > yearDiv.StartYear {
            yearDiv.ADirection = 1
        } else {
            yearDiv.ADirection = 2
        }
        if inCalendar.UseAnimation {
            yearDiv.ATick = yearDiv.ATotalTick
        }
        yearDiv.StartYear = startYear
    }
}

/*
* 选择年份
* calendar:日历
* monthDiv:月层
* year:年
*/
func SelectYear(calendar *FCView, monthDiv *MonthDiv, year int) {
    inCalendar := calendar.GetCalendar()
    if monthDiv.Year != year {
        if year > monthDiv.Year {
            monthDiv.ADirection = 1
        }else {
            monthDiv.ADirection = 2
        }
        if inCalendar.UseAnimation {
            monthDiv.ATick = monthDiv.ATotalTick
        }
        monthDiv.Year = year
    }
}

/*
* 选中日期
* calendar:日历
* dayDiv:日期层
* selectedDay:选中日
* lastDay:上一日
*/
func SelectDay(calendar *FCView, dayDiv *DayDiv, selectedDay *CDay, lastDay *CDay) {
    inCalendar := calendar.GetCalendar()
    m := GetYear(calendar, selectedDay.Year).Months[selectedDay.Month]
    thisMonth := GetYear(calendar, lastDay.Year).Months[lastDay.Month]
    if m != thisMonth {
        if thisMonth.Year * 12 + thisMonth.Month > m.Year * 12 + m.Month {
            dayDiv.ADirection = 2
        }else {
            dayDiv.ADirection = 1
        }
        buttonSize := len(dayDiv.DayButtons)
        for i := 0; i < buttonSize; i++ {
            dayButton := dayDiv.DayButtons[i]
            if (dayDiv.ADirection == 1 && dayButton.GetDay() == thisMonth.Days[0]) || (dayDiv.ADirection == 2 && dayButton.GetDay() == thisMonth.Days[len(thisMonth.Days) - 1]) {
                dayDiv.AClickRowFrom = int(i / 7)
                if i % 7 != 0{
                    dayDiv.AClickRowFrom += 1
                }
            }
        }
        ResetDayDiv(calendar, dayDiv, 0)
        buttonSize = len(dayDiv.DayButtonsAm)
        for i := 0; i < buttonSize; i++ {
            dayFCButtonm := dayDiv.DayButtonsAm[i]
            if (dayDiv.ADirection == 1 && dayFCButtonm.GetDay() == m.Days[0]) || (dayDiv.ADirection == 2 && dayFCButtonm.GetDay() == m.Days[len(m.Days) - 1]) {
                dayDiv.AClickRowTo = int(i / 7)
                if i % 7 != 0 {
                    dayDiv.AClickRowTo += 1
                }
            }
        }
        if inCalendar.UseAnimation {
            dayDiv.ATick = dayDiv.ATotalTick
        }
    } else {
        dayButtonsSize := len(dayDiv.DayButtons)
        for i := 0; i < dayButtonsSize; i++ {
            dayButton := dayDiv.DayButtons[i]
            if dayButton.GetDay() != selectedDay {
                dayButton.Selected = false
            }
        }
    }
}

/*
* 更新日历的布局
* calendar:日历
*/
func UpdateCalendar(calendar *FCView) {
    inCalendar := calendar.GetCalendar()
    headDiv := inCalendar.GetHeadDiv()
    headDiv.Bounds = CreateRect(0, 0, calendar.Size.Cx, 80)
    if inCalendar.Mode == "day" {
        ResetDayDiv(calendar, inCalendar.GetDayDiv(), 0)
        ResetDayDiv(calendar, inCalendar.GetDayDiv(), 1)
    } else if inCalendar.Mode == "month" {
        ResetMonthDiv(calendar, inCalendar.GetMonthDiv(), 0)
        ResetMonthDiv(calendar, inCalendar.GetMonthDiv(), 1)
    }else if inCalendar.Mode == "year" {
        ResetYearDiv(calendar, inCalendar.GetYearDiv(), 0)
        ResetYearDiv(calendar, inCalendar.GetYearDiv(), 1)
    }
}

/*
* 绘制头部层
* calendar:日历
* headDiv:头部层
* paint:绘图对象
*/
func DrawHeadDiv(calendar *FCView, headDiv *HeadDiv, paint *FCPaint) {
    inCalendar := calendar.GetCalendar()
    bounds := headDiv.Bounds
    if headDiv.BackColor != "none" {
        paint.FillRect(headDiv.BackColor, bounds.Left, bounds.Top, bounds.Right, bounds.Bottom)
    }
    var weekStrings []string
    weekStrings = append(weekStrings, "周日")
    weekStrings = append(weekStrings, "周一")
    weekStrings = append(weekStrings, "周二")
    weekStrings = append(weekStrings, "周三")
    weekStrings = append(weekStrings, "周四")
    weekStrings = append(weekStrings, "周五")
    weekStrings = append(weekStrings, "周六")
    w := bounds.Right - bounds.Left
    left := bounds.Left
    for i := 0; i < 7; i++ {
        weekDaySize := paint.TextSize(weekStrings[i], headDiv.WeekFont)
        textX := left + (w / 7) / 2 - weekDaySize.Cx / 2
        textY := bounds.Bottom - weekDaySize.Cy - 2
        paint.DrawText(weekStrings[i], headDiv.TextColor, headDiv.WeekFont, textX, textY)
        left += w / 7
    }
    drawTitle := ""
    selectedDay := inCalendar.GetSelectedDay()
    if inCalendar.Mode == "day" {
        drawTitle = ToFixed(float64(selectedDay.Year), 0) + "年" + ConvertIntToStr(selectedDay.Month) + "月"
    } else if inCalendar.Mode == "month" {
        monthDiv := inCalendar.GetMonthDiv()
        drawTitle = ToFixed(float64(monthDiv.Year), 0) + "年"
    } else {
        yearDiv := inCalendar.GetYearDiv()
        drawTitle = ToFixed(float64(yearDiv.StartYear), 0) + "年-" + ConvertIntToStr(yearDiv.StartYear + 11) + "年"
    }
    tSize := paint.TextSize(drawTitle, headDiv.TitleFont)
    paint.DrawText(drawTitle, headDiv.TextColor, headDiv.TitleFont, bounds.Left + (w - tSize.Cx) / 2, 30)
    tR := 10.0
    var drawPoints []FCPoint
	drawPoints = append(drawPoints, CreatePoint(5, bounds.Top + (bounds.Bottom - bounds.Top) / 2))
	drawPoints = append(drawPoints, CreatePoint(5 + tR * 2, bounds.Top + (bounds.Bottom - bounds.Top) / 2 - tR))
	drawPoints = append(drawPoints, CreatePoint(5 + tR * 2, bounds.Top + (bounds.Bottom - bounds.Top) / 2 + tR))
	paint.FillPolygon(headDiv.ArrowColor, drawPoints)
	var drawPoints2 []FCPoint
	drawPoints2 = append(drawPoints2, CreatePoint(bounds.Right - 5, bounds.Top + (bounds.Bottom - bounds.Top) / 2))
	drawPoints2 = append(drawPoints2, CreatePoint(bounds.Right - 5 - tR * 2, bounds.Top + (bounds.Bottom - bounds.Top) / 2 - tR))
	drawPoints2 = append(drawPoints2, CreatePoint(bounds.Right - 5 - tR * 2, bounds.Top + (bounds.Bottom - bounds.Top) / 2 + tR))
	paint.FillPolygon(headDiv.ArrowColor, drawPoints2)
}

/*
* 绘制日的按钮
* calendar:日历
* dayButton:日期按钮
* paint:绘图对象
*/
func DrawDayButton(calendar *FCView, dayButton *DayButton, paint *FCPaint) {
    cDay := dayButton.GetDay()
    if cDay.IsNotEmpty {
        bounds := dayButton.Bounds
        text := ConvertIntToStr(cDay.Day)
        if dayButton.BackColor != "none" {
            paint.FillRect(dayButton.BackColor, bounds.Left + 2, bounds.Top + 2, bounds.Right - 2, bounds.Bottom - 2)
        }
        if dayButton.InThisMonth {
            paint.DrawText(text, dayButton.TextColor, dayButton.Font, bounds.Left + 5, bounds.Top + 7)
        } else {
            paint.DrawText(text, dayButton.TextColor2, dayButton.Font, bounds.Left + 5, bounds.Top + 7)
        }
        if dayButton.BorderColor != "none" {
            paint.DrawRect(dayButton.BorderColor, 1, 0, bounds.Left + 2, bounds.Top + 2, bounds.Right - 2, bounds.Bottom - 2)
        }
    }
}

/*
* 绘制月的按钮
* calendar:日历
* monthButton:月按钮
* paint:绘图对象
*/
func DrawMonthButton(calendar *FCView, monthButton *MonthButton, paint *FCPaint) {
    bounds := monthButton.Bounds
    text := GetMonthStr(monthButton.Month)
    if monthButton.BackColor != "none" {
        paint.FillRect(monthButton.BackColor, bounds.Left + 2, bounds.Top + 2, bounds.Right - 2, bounds.Bottom - 2)
    }
    paint.DrawText(text, monthButton.TextColor, monthButton.Font, bounds.Left + 5, bounds.Top + 7)
    if monthButton.BorderColor != "none" {
        paint.DrawRect(monthButton.BorderColor, 1, 0, bounds.Left + 2, bounds.Top + 2, bounds.Right - 2, bounds.Bottom - 2)
    }
}

/*
* 绘制年的按钮
* calendar:日历
* yearButton:年按钮
* paint:绘图对象
*/
func DrawYearButton(calendar *FCView, yearButton *YearButton, paint *FCPaint) {
    bounds := yearButton.Bounds
    text := ConvertIntToStr(yearButton.Year)
    if yearButton.BackColor != "none" {
        paint.FillRect(yearButton.BackColor, bounds.Left + 2, bounds.Top + 2, bounds.Right - 2, bounds.Bottom - 2)
    }
    paint.DrawText(text, yearButton.TextColor, yearButton.Font, bounds.Left + 5, bounds.Top + 7)
    if yearButton.BorderColor != "none" {
        paint.DrawRect(yearButton.BorderColor, 1, 0, bounds.Left + 2, bounds.Top + 2, bounds.Right - 2, bounds.Bottom - 2)
    }
}

/*
* 绘制日历
* calendar:日历
* paint:绘图对象
*/
func DrawCalendar(calendar *FCView, paint *FCPaint) {
    inCalendar := calendar.GetCalendar()
    dayDiv := inCalendar.GetDayDiv()
    monthDiv := inCalendar.GetMonthDiv()
    yearDiv := inCalendar.GetYearDiv()
    if calendar.BackColor != "none" {
        paint.FillRect(calendar.BackColor, 0, 0, calendar.Size.Cx, calendar.Size.Cy)
    }
    if inCalendar.Mode == "day" {
        dayButtonsSize := len(dayDiv.DayButtons)
        for i := 0; i < dayButtonsSize; i++ {
            dayButton := dayDiv.DayButtons[i]
            if dayButton.Visible {
                if paint.OnPaintCalendarDayButton != nil{
                    paint.OnPaintCalendarDayButton(calendar, dayButton, paint)
                }else{
                    DrawDayButton(calendar, dayButton, paint)
                }
            }
        }
        dayFCButtonmSize := len(dayDiv.DayButtonsAm)
        for i := 0; i < dayFCButtonmSize; i++ {
            dayButton := dayDiv.DayButtonsAm[i]
            if dayButton.Visible {
                if paint.OnPaintCalendarDayButton != nil{
                    paint.OnPaintCalendarDayButton(calendar, dayButton, paint)
                }else{
                    DrawDayButton(calendar, dayButton, paint)
                }
            }
        }
    }else if inCalendar.Mode == "month" {
        monthButtonsSize := len(monthDiv.MonthButtons)
        for i := 0; i < monthButtonsSize; i++ {
            monthButton := monthDiv.MonthButtons[i]
            if monthButton.Visible {
                if paint.OnPaintCalendarMonthButton != nil{
                    paint.OnPaintCalendarMonthButton(calendar, monthButton, paint)
                }else{
                    DrawMonthButton(calendar, monthButton, paint)
                }
            }
        }
        monthFCButtonmSize := len(monthDiv.MonthButtonsAm)
        for i := 0; i < monthFCButtonmSize; i++ {
            monthButton := monthDiv.MonthButtonsAm[i]
            if monthButton.Visible {
                if paint.OnPaintCalendarMonthButton != nil{
                    paint.OnPaintCalendarMonthButton(calendar, monthButton, paint)
                }else{
                    DrawMonthButton(calendar, monthButton, paint)
                }
            }
        }
    } else if inCalendar.Mode == "year" {
        yearButtonsSize := len(yearDiv.YearButtons)
        for i := 0; i < yearButtonsSize; i++ {
            yearButton := yearDiv.YearButtons[i]
            if yearButton.Visible {
                if paint.OnPaintCalendarYearButton != nil{
                    paint.OnPaintCalendarYearButton(calendar, yearButton, paint)
                }else{
                    DrawYearButton(calendar, yearButton, paint)
                }
            }
        }
        yearFCButtonmSize := len(yearDiv.YearButtonsAm)
        for i := 0; i < yearFCButtonmSize; i++ {
            yearButton := yearDiv.YearButtonsAm[i]
            if (yearButton.Visible) {
                if(paint.OnPaintCalendarYearButton != nil){
                    paint.OnPaintCalendarYearButton(calendar, yearButton, paint)
                }else{
                    DrawYearButton(calendar, yearButton, paint)
                }
            }
        }
    }
    if paint.OnPaintCalendarHeadDiv != nil{
        paint.OnPaintCalendarHeadDiv(calendar, inCalendar.GetHeadDiv(), paint)
    }else{
        DrawHeadDiv(calendar, inCalendar.GetHeadDiv(), paint)
    }
    if calendar.BorderColor != "none" {
        paint.DrawRect(calendar.BorderColor, 1, 0, 0, 0, calendar.Size.Cx, calendar.Size.Cy)
    }
}

/*
* 点击日的按钮
* calendar:日历
* dayButton:日期按钮
* mp:坐标
*/
func ClickDayButton(calendar *FCView, dayButton *DayButton, mp FCPoint) {
    inCalendar := calendar.GetCalendar()
    lastDay := inCalendar.GetSelectedDay()
    inCalendar.SetSelectedDay(dayButton.GetDay())
    SelectDay(calendar, inCalendar.GetDayDiv(), inCalendar.GetSelectedDay(), lastDay)
    UpdateCalendar(calendar)
    InvalidateView(calendar)
}

/*
* 点击月的按钮
* calendar:日历
* monthButton:月按钮
* mp:坐标
*/
func ClickMonthButton(calendar *FCView, monthButton *MonthButton, mp FCPoint) {
    inCalendar := calendar.GetCalendar()
    month := GetYear(calendar, monthButton.Year).Months[monthButton.Month]
    inCalendar.Mode = "day"
    lastDay := inCalendar.GetSelectedDay()
    inCalendar.SetSelectedDay(month.Days[1])
    SelectDay(calendar, inCalendar.GetDayDiv(), inCalendar.GetSelectedDay(), lastDay)
    UpdateCalendar(calendar)
    InvalidateView(calendar)
}

/*
* 点击年的按钮
* calendar:日历
* yearButton:年按钮
* mp:坐标
*/
func ClickYearButton(calendar *FCView, yearButton *YearButton, mp FCPoint) {
    inCalendar := calendar.GetCalendar()
    inCalendar.Mode = "month"
    SelectYear(calendar, inCalendar.GetMonthDiv(), yearButton.Year)
    UpdateCalendar(calendar)
    InvalidateView(calendar)
}

/*
* 点击左侧的按钮
* calendar:日历
* headDiv:头部层
* mp:坐标
*/
func ClickLastButton(calendar *FCView, headDiv *HeadDiv, mp FCPoint) {
    inCalendar := calendar.GetCalendar()
    if inCalendar.Mode == "day"{
        lastMonth := GetLastMonth(calendar, inCalendar.GetSelectedDay().Year, inCalendar.GetSelectedDay().Month)
        lastDay := inCalendar.GetSelectedDay()
        inCalendar.SetSelectedDay(lastMonth.Days[1])
        SelectDay(calendar, inCalendar.GetDayDiv(), inCalendar.GetSelectedDay(), lastDay)
        UpdateCalendar(calendar)
        InvalidateView(calendar)
    } else if inCalendar.Mode == "month" {
        year := inCalendar.GetMonthDiv().Year
        year -= 1
        SelectYear(calendar, inCalendar.GetMonthDiv(), year)
        UpdateCalendar(calendar)
        InvalidateView(calendar)
    } else if inCalendar.Mode == "year" {
        year := inCalendar.GetYearDiv().StartYear
        year -= 12
        SelectStartYear(calendar, inCalendar.GetYearDiv(), year)
        UpdateCalendar(calendar)
        InvalidateView(calendar)
    }
}

/*
* 点击右侧的按钮
* calendar:日历
* headDiv:头部层
* mp:坐标
*/
func ClickNextButton(calendar *FCView, headDiv *HeadDiv, mp FCPoint) {
    inCalendar := calendar.GetCalendar()
    if inCalendar.Mode == "day" {
        nextMonth := GetNextMonth(calendar, inCalendar.GetSelectedDay().Year, inCalendar.GetSelectedDay().Month)
        lastDay := inCalendar.GetSelectedDay()
        inCalendar.SetSelectedDay(nextMonth.Days[1])
        SelectDay(calendar, inCalendar.GetDayDiv(), inCalendar.GetSelectedDay(), lastDay)
        UpdateCalendar(calendar)
        InvalidateView(calendar)
    } else if inCalendar.Mode == "month" {
        year := inCalendar.GetMonthDiv().Year
        year += 1
        SelectYear(calendar, inCalendar.GetMonthDiv(), year)
        UpdateCalendar(calendar)
        InvalidateView(calendar)
    } else if inCalendar.Mode == "year" {
        year := inCalendar.GetYearDiv().StartYear
        year += 12
        SelectStartYear(calendar, inCalendar.GetYearDiv(), year)
        UpdateCalendar(calendar)
        InvalidateView(calendar)
    }
}

/*
* 改变模式的按钮
* calendar:日历
* headDiv:头部层
* mp:坐标
*/
func ClickModeButton(calendar *FCView, headDiv *HeadDiv, mp FCPoint) {
    inCalendar := calendar.GetCalendar()
    monthDiv := inCalendar.GetMonthDiv()
    yearDiv := inCalendar.GetYearDiv()
    if inCalendar.Mode == "day" {
        inCalendar.Mode = "month"
        monthDiv.Month = inCalendar.GetSelectedDay().Month
        monthDiv.Year = inCalendar.GetSelectedDay().Year
        UpdateCalendar(calendar)
       InvalidateView(calendar)
    }else if inCalendar.Mode == "month" {
        inCalendar.Mode = "year"
        SelectStartYear(calendar, yearDiv, monthDiv.Year)
        UpdateCalendar(calendar)
        InvalidateView(calendar)
    }
}

/*
* 点击日历
* calendar:日历
* mp:坐标
*/
func ClickCalendar(calendar *FCView, mp FCPoint) {
    inCalendar := calendar.GetCalendar()
    headDiv := inCalendar.GetHeadDiv()
    dayDiv := inCalendar.GetDayDiv()
    monthDiv := inCalendar.GetMonthDiv()
    yearDiv := inCalendar.GetYearDiv()
    headBounds := headDiv.Bounds
    if mp.X >= headBounds.Left && mp.X <= headBounds.Right && mp.Y >= headBounds.Top && mp.Y <= headBounds.Bottom {
        tR := 10.0
        if mp.X < headBounds.Left + tR * 3 {
            ClickLastButton(calendar, inCalendar.GetHeadDiv(), mp)
            return
        } else if mp.X > headBounds.Right - tR * 3 {
            ClickNextButton(calendar, inCalendar.GetHeadDiv(), mp)
            return
        } else {
            ClickModeButton(calendar, inCalendar.GetHeadDiv(), mp)
            return
        }
    }
    if inCalendar.Mode == "day" {
        dayButtonsSize := len(dayDiv.DayButtons)
        for i := 0; i < dayButtonsSize; i++ {
            dayButton := dayDiv.DayButtons[i]
            if dayButton.Visible {
                bounds := dayButton.Bounds
                if mp.X >= bounds.Left && mp.X <= bounds.Right && mp.Y >= bounds.Top && mp.Y <= bounds.Bottom {
                    ClickDayButton(calendar, dayButton, mp)
                    return
                }
            }
        }
    }else if inCalendar.Mode == "month" {
        monthButtonsSize := len(monthDiv.MonthButtons)
        for i := 0; i < monthButtonsSize; i++ {
            monthButton := monthDiv.MonthButtons[i]
            if monthButton.Visible {
                bounds := monthButton.Bounds
                if mp.X >= bounds.Left && mp.X <= bounds.Right && mp.Y >= bounds.Top && mp.Y <= bounds.Bottom {
                    ClickMonthButton(calendar, monthButton, mp)
                    return
                }
            }
        }
    } else if inCalendar.Mode == "year" {
        yearButtonsSize := len(yearDiv.YearButtons)
        for i := 0; i < yearButtonsSize; i++ {
            yearButton := yearDiv.YearButtons[i]
            if yearButton.Visible {
                bounds := yearButton.Bounds
                if mp.X >= bounds.Left && mp.X <= bounds.Right && mp.Y >= bounds.Top && mp.Y <= bounds.Bottom {
                    ClickYearButton(calendar, yearButton, mp)
                    return
                }
            }
        }
    }
}

/*
* 绘制滚动条
* div:图层
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawDivScrollBar(div *FCView, paint *FCPaint, clipRect FCRect) {
    div.HScrollIsVisible = false
    div.VScrollIsVisible = false
    //绘制滚动条
    if div.ShowHScrollBar {
        contentWidth := GetDivContentWidth(div)
        if contentWidth > 0 && contentWidth > div.Size.Cx {
            sLeft := div.ScrollH / contentWidth * div.Size.Cx
            sRight := (div.ScrollH + div.Size.Cx) / contentWidth * div.Size.Cx
            if sRight - sLeft < div.ScrollSize {
                sRight = sLeft + div.ScrollSize
            }
            if paint.GetTouchMoveView() == div && (div.HoverScrollHButton || div.DownScrollHButton) {
                paint.FillRect(div.ScrollBarHoveredColor, sLeft, div.Size.Cy - div.ScrollSize, sRight, div.Size.Cy)
            } else {
                paint.FillRect(div.ScrollBarColor, sLeft, div.Size.Cy - div.ScrollSize, sRight, div.Size.Cy)
            }
            div.HScrollIsVisible = true
        }
    }
    if div.ShowVScrollBar {
        contentHeight := GetDivContentHeight(div)
        if contentHeight > 0 && contentHeight > div.Size.Cy {
            sTop := div.ScrollV / contentHeight * div.Size.Cy
            sBottom := sTop + (div.Size.Cy / contentHeight * div.Size.Cy)
            if sBottom - sTop < div.ScrollSize {
                sBottom = sTop + div.ScrollSize
            }
            if paint.GetTouchMoveView() == div && (div.HoverScrollVButton || div.DownScrollVButton) {
                paint.FillRect(div.ScrollBarHoveredColor, div.Size.Cx - div.ScrollSize, sTop, div.Size.Cx, sBottom)
            } else {
                paint.FillRect(div.ScrollBarColor, div.Size.Cx - div.ScrollSize, sTop, div.Size.Cx, sBottom)
            }
            div.VScrollIsVisible = true
        }
    }
}

/*
* 获取内容的宽度
* div:图层
*/
func GetDivContentWidth(div *FCView)(float64) {
    cWidth := 0.0
    if len(div.Views) > 0 {
        for i := 0; i < len(div.Views); i++ {
            if div.Views[i].Visible {
                if (cWidth < div.Views[i].Location.X + div.Views[i].Size.Cx) {
                    cWidth = div.Views[i].Location.X + div.Views[i].Size.Cx
                }
            }
        }
    }
    return cWidth
}

/*
* 获取内容的高度
* div:图层
*/
func GetDivContentHeight(div *FCView)(float64) {
    cHeight := 0.0
    if len(div.Views) > 0 {
        for i := 0; i < len(div.Views); i++ {
            if div.Views[i].Visible {
                if (cHeight < div.Views[i].Location.Y + div.Views[i].Size.Cy) {
                    cHeight = div.Views[i].Location.Y + div.Views[i].Size.Cy
                }
            }
        }
    }
    return cHeight
}

/*
* 图层的鼠标移动方法
* div: 图层
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func TouchMoveDiv(div *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint) {
    div.HoverScrollHButton = false
    div.HoverScrollVButton = false
    paint := div.GetPaint()
    mp := CreatePoint(firstPoint.X, firstPoint.Y)
    if firstTouch {
        if div.ShowHScrollBar || div.ShowVScrollBar {
            if div.DownScrollHButton {
                contentWidth := GetDivContentWidth(div)
                subX := (mp.X - div.StartPoint.X) / div.Size.Cx * contentWidth
                newScrollH := div.StartScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - div.Size.Cx {
                    newScrollH = contentWidth - div.Size.Cx
                }
                div.ScrollH = newScrollH
                paint.CancelClick = true
                return

            } else if div.DownScrollVButton {
                contentHeight := GetDivContentHeight(div)
                subY := (mp.Y - div.StartPoint.Y) / div.Size.Cy * contentHeight
                newScrollV := div.StartScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - div.Size.Cy {
                    newScrollV = contentHeight - div.Size.Cy
                }
                div.ScrollV = newScrollV
                paint.CancelClick = true
                return
            }
        }
        if div.AllowDragScroll {
            contentWidth := GetDivContentWidth(div)
            if contentWidth > div.Size.Cx {
                subX := div.StartPoint.X - mp.X
                newScrollH := div.StartScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - div.Size.Cx{
                    newScrollH = contentWidth - div.Size.Cx
                }
                div.ScrollH = newScrollH
                if subX > 5 || subX < -5 {
                    paint.CancelClick = true
                }
            }
            contentHeight := GetDivContentHeight(div)
            if contentHeight > div.Size.Cy {
                subY := div.StartPoint.Y - mp.Y
                newScrollV := div.StartScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - div.Size.Cy {
                    newScrollV = contentHeight - div.Size.Cy
                }
                div.ScrollV = newScrollV
                if subY > 5 || subY < -5 {
                    paint.CancelClick = true
                }
            }
        }
    } else {
        if div.ShowHScrollBar {
            contentWidth := GetDivContentWidth(div)
            if contentWidth > 0 && contentWidth > div.Size.Cx {
                sLeft := div.ScrollH / contentWidth * div.Size.Cx
                sRight := (div.ScrollH + div.Size.Cx) / contentWidth * div.Size.Cx
                if sRight - sLeft < div.ScrollSize {
                    sRight = sLeft + div.ScrollSize
                }
                if mp.X >= sLeft && mp.X <= sRight && mp.Y >= div.Size.Cy - div.ScrollSize && mp.Y <= div.Size.Cy {
                    div.HoverScrollHButton = true
                    return
                } else {
                    div.HoverScrollHButton = false
                }
            }
        }
        if div.ShowVScrollBar {
            contentHeight := GetDivContentHeight(div)
            if contentHeight > 0 && contentHeight > div.Size.Cy{
                sTop := div.ScrollV / contentHeight * div.Size.Cy
                sBottom := (div.ScrollV + div.Size.Cy) / contentHeight * div.Size.Cy
                if sBottom - sTop < div.ScrollSize {
                    sBottom = sTop + div.ScrollSize
                }
                if mp.X >= div.Size.Cx - div.ScrollSize && mp.X <= div.Size.Cx && mp.Y >= sTop && mp.Y <= sBottom{
                    div.HoverScrollVButton = true
                    return
                } else {
                    div.HoverScrollVButton = false
                }
            }
        }
    }
}

/*
* 图层的鼠标按下方法
* div: 图层
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func TouchDownDiv(div *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int) {
    mp := CreatePoint(firstPoint.X, firstPoint.Y)
    div.StartPoint = mp
    div.DownScrollHButton = false
    div.DownScrollVButton = false
    div.HoverScrollHButton = false
    div.HoverScrollVButton = false
    if div.ShowHScrollBar {
        contentWidth := GetDivContentWidth(div)
        if contentWidth > 0 && contentWidth > div.Size.Cx {
            sLeft := div.ScrollH / contentWidth * div.Size.Cx
            sRight := (div.ScrollH + div.Size.Cx) / contentWidth * div.Size.Cx
            if sRight - sLeft < div.ScrollSize {
                sRight = sLeft + div.ScrollSize
            }
            if mp.X >= sLeft && mp.X <= sRight && mp.Y >= div.Size.Cy - div.ScrollSize && mp.Y <= div.Size.Cy {
                div.DownScrollHButton = true
                div.StartScrollH = div.ScrollH
                return
            }
        }
    }
    if div.ShowVScrollBar {
        contentHeight := GetDivContentHeight(div)
        if contentHeight > 0 && contentHeight > div.Size.Cy {
            sTop := div.ScrollV / contentHeight * div.Size.Cy
            sBottom := (div.ScrollV + div.Size.Cy) / contentHeight * div.Size.Cy
            if sBottom - sTop < div.ScrollSize{
                sBottom = sTop + div.ScrollSize
            }
            if mp.X >= div.Size.Cx - div.ScrollSize && mp.X <= div.Size.Cx && mp.Y >= sTop && mp.Y <= sBottom {
                div.DownScrollVButton = true
                div.StartScrollV = div.ScrollV
                return
            }
        }
    }
    if div.AllowDragScroll {
        div.StartScrollH = div.ScrollH
        div.StartScrollV = div.ScrollV
    }
}

/*
* 图层的鼠标抬起方法
* div: 图层
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func TouchUpDiv(div *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int) {
    div.HoverScrollHButton = false
    div.HoverScrollVButton = false
    div.DownScrollHButton = false
    div.DownScrollVButton = false
}

/*
* 图层的鼠标滚轮方法
* div:图层
* delta:滚轮值
*/
func TouchWheelDiv(div *FCView, delta int) {
    oldScrollV := div.ScrollV
    if delta > 0 {
        oldScrollV -= 10
    } else if delta < 0 {
        oldScrollV += 10
    }
    contentHeight := GetDivContentHeight(div)
    if contentHeight < div.Size.Cy {
        div.ScrollV = 0
    } else {
        if oldScrollV < 0{
            oldScrollV = 0
        } else if oldScrollV > contentHeight - div.Size.Cy {
            oldScrollV = contentHeight - div.Size.Cy
        }
        div.ScrollV = oldScrollV
    }
}

/*
* 重绘图层
* div:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawDiv(div *FCView, paint *FCPaint, clipRect FCRect) {
    if div.BackColor != "none" {
        paint.FillRoundRect(div.BackColor, 0, 0, div.Size.Cx, div.Size.Cy, div.CornerRadius)
    }
}

/*
 * 快速添加表格列
 * grid:表格
 * columns:列名集合
 */
func FastAddGridColumns(grid *FCView, columns []string){
    inGrid := grid.GetGrid()
    columnsSize := len(columns)
    for i := 0; i < columnsSize; i++ {
        gridColumn := CreateGridColumn()
        gridColumn.Text = columns[i]
        inGrid.Columns = append(inGrid.Columns, gridColumn)
    }
}

/*
 * 添加视图到单元格
 * view:视图
 * cell:单元格
 * grid:表格
 */
func AddViewToGridCell(view *FCView, cell *FCGridCell, grid *FCView){
    view.DisplayOffset = false
    view.Visible = false
    cell.SetView(view)
    AddViewToParent(view, grid)
}

/*
 * 快速添加表格行
 * grid:表格
 * datas:数据集合
 */
func FastAddGridRow(grid *FCView, datas []string)(*FCGridRow) {
    gridRow := CreateGridRow()
    datasSize := len(datas)
    for i := 0; i < datasSize; i++ {
        gridCell := CreateGridCell()
        gridCell.Value = datas[i]
        gridRow.Cells = append(gridRow.Cells, gridCell)
    }
    return gridRow
}

/*
* 重绘图层边线
* div:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawDivBorder(div *FCView, paint *FCPaint, clipRect FCRect) {
    if div.BorderColor != "none" {
        paint.DrawRoundRect(div.BorderColor, div.BorderWidth, 0, 0, 0, div.Size.Cx, div.Size.Cy, div.CornerRadius)
    }
}

/*
* 绘制单元格
* grid:表格
* row:行
* column:列
* cell:单元格
* paint:绘图对象
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func DrawGridCell(grid *FCView, row *FCGridRow, column *FCGridColumn, cell *FCGridCell, paint *FCPaint, left float64, top float64, right float64, bottom float64) {
    inGrid := grid.GetGrid()    
    if cell.BackColor != "none" {
        paint.FillRect(cell.BackColor, left, top, right, bottom)
    }
    if row.Selected{
        if inGrid.SelectedRowColor != "none" {
            paint.FillRect(inGrid.SelectedRowColor, left, top, right, bottom)
        }
    }
    if cell.BorderColor != "none" {
        //paint.DrawRect(cell.BorderColor, 1, 0, left, top, right, bottom)
        paint.DrawRect(cell.BorderColor, 1, 0, left, bottom, right, bottom)
		paint.DrawRect(cell.BorderColor, 1, 0, right - 1, top, right - 1, bottom)
    }
    if len(cell.Value) > 0 {
        showText := cell.Value
        if (column.ColType == "double") {
			if (cell.Digit >= 0) {
				numValue := ConvertToFloat64(showText)
				showText = ToFixed(numValue, cell.Digit)
			}
		}
        tSize := paint.TextSize(showText, cell.Font)
        if tSize.Cx > right - left{
            paint.DrawTextAutoEllipsis(showText, cell.TextColor, cell.Font, left + 2, top + inGrid.RowHeight / 2 - tSize.Cy / 2, right - 2, top + inGrid.RowHeight / 2 + tSize.Cy / 2)
        }else{
            if column.CellAlign == "left"{
                paint.DrawText(showText, cell.TextColor, cell.Font, left + 2, top + inGrid.RowHeight / 2 - tSize.Cy / 2)
            }else if column.CellAlign == "center"{
                paint.DrawText(showText, cell.TextColor, cell.Font, left + (right - left - tSize.Cx) / 2, top + inGrid.RowHeight / 2 - tSize.Cy / 2)
            }else if column.CellAlign == "right"{
                paint.DrawText(showText, cell.TextColor, cell.Font, right - tSize.Cx, top + inGrid.RowHeight / 2 - tSize.Cy / 2)
            }
        }
    }
}

/*
* 绘制列
* grid:表格
* column:列
* paint:绘图对象
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func DrawGridColumn(grid *FCView, column *FCGridColumn, paint *FCPaint, left float64, top float64, right float64, bottom float64) {
    inGrid := grid.GetGrid()    
    tSize := paint.TextSize(column.Text, column.Font)
    if column.BackColor != "none" {
        paint.FillRect(column.BackColor, left, top, right, bottom)
    }
    if column.BorderColor != "none" {
        paint.DrawRect(column.BorderColor, 1, 0, left, top, right, bottom)
    }
    paint.DrawText(column.Text, column.TextColor, column.Font, left + (column.Width - tSize.Cx) / 2, top + (inGrid.HeaderHeight - tSize.Cy) / 2)
    if column.Sort == "asc" {
        cR := (bottom - top) / 4
        oX := right - cR * 2
        oY := top + (bottom - top) / 2
        var drawPoints []FCPoint
		drawPoints = append(drawPoints, CreatePoint(oX, oY - cR))
		drawPoints = append(drawPoints, CreatePoint(oX - cR, oY + cR))
		drawPoints = append(drawPoints, CreatePoint(oX + cR, oY + cR))
		paint.FillPolygon(column.TextColor, drawPoints)
    }else if column.Sort == "desc" {
        cR := (bottom - top) / 4
        oX := right - cR * 2
        oY := top + (bottom - top) / 2
        var drawPoints []FCPoint
		drawPoints = append(drawPoints, CreatePoint(oX, oY + cR))
		drawPoints = append(drawPoints, CreatePoint(oX - cR, oY - cR))
		drawPoints = append(drawPoints, CreatePoint(oX + cR, oY - cR))
        paint.FillPolygon(column.TextColor, drawPoints)
    }
}

/*
* 绘制表格
* grid:表格
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawGrid(grid *FCView, paint *FCPaint, clipRect FCRect) {
    inGrid := grid.GetGrid()    
    cTop := -grid.ScrollV + inGrid.HeaderHeight
    //绘制行
    colLeft := 0.0
    if len(grid.Views) > 0{
        for i := 0; i < len(grid.Views); i++ {
            grid.Views[i].Visible = false
        }
    }
    if len(inGrid.Columns) > 0{
        for i := 0; i < len(inGrid.Columns); i++ {
            if(len(inGrid.Columns[i].WidthStr) > 0){
                newWidthStr := strings.Replace(inGrid.Columns[i].WidthStr, "(", "", -1)
                inGrid.Columns[i].Width = ConvertToFloat64(newWidthStr) * grid.Size.Cx / 100
            }
            colRect := CreateRect(colLeft, 0, colLeft + inGrid.Columns[i].Width, inGrid.HeaderHeight)
            inGrid.Columns[i].Bounds = colRect
            inGrid.Columns[i].Index = i
            colLeft += inGrid.Columns[i].Width
        }
    }
    if len(inGrid.Rows) > 0{
        for i := 0; i < len(inGrid.Rows); i++ {
            row := inGrid.Rows[i]
            row.Index = i
            if row.Visible {
                rTop := cTop
                rBottom := cTop + inGrid.RowHeight
                if rBottom >= 0 && cTop <= grid.Size.Cy {
                    for j := 0; j < len(row.Cells); j++ {
                        cell := row.Cells[j]
                        gridColumn := cell.GetColumn()
                        if !gridColumn.IsNotEmpty {
                            gridColumn = inGrid.Columns[j]
                        }
                        if gridColumn.Visible {
                            if !gridColumn.Frozen {
                                cellWidth := gridColumn.Width
                                colSpan := cell.ColSpan
                                if colSpan > 1 {
                                    for n := 1; n < colSpan; n++ {
                                        spanColumn := inGrid.Columns[gridColumn.Index + n]
                                        if spanColumn.IsNotEmpty && spanColumn.Visible {
                                            cellWidth += spanColumn.Width
                                        }
                                    }
                                }
                                cellHeight := inGrid.RowHeight
                                rowSpan := cell.RowSpan
                                if rowSpan > 1 {
                                    for n := 1; n < rowSpan; n++ {
                                        spanRow := inGrid.Rows[i + n]
                                        if spanRow.IsNotEmpty && spanRow.Visible {
                                            cellHeight += inGrid.RowHeight
                                        }
                                    }
                                }
                                cRect := CreateRect(gridColumn.Bounds.Left - grid.ScrollH, rTop, gridColumn.Bounds.Left + cellWidth - grid.ScrollH, rTop + cellHeight)
                                if cRect.Right >= 0 && cRect.Left < grid.Size.Cx {
                                    if paint.OnPaintGridCell != nil{
                                        paint.OnPaintGridCell(grid, row, gridColumn, cell, paint, cRect.Left, cRect.Top, cRect.Right, cRect.Bottom)
                                    }else{
                                        DrawGridCell(grid, row, gridColumn, cell, paint, cRect.Left, cRect.Top, cRect.Right, cRect.Bottom)
                                    }
                                    if len(cell.View) > 0{
                                        cellView := cell.GetView()
                                        cellView.Visible = true
                                        cellView.Location = CreatePoint(cRect.Left + grid.ScrollH, cRect.Top + grid.ScrollV)
                                        cellView.Size = CreateSize(cRect.Right - cRect.Left, cRect.Bottom - cRect.Top)
                                    }
                                }
                            }
                        }
                    }
                }
                if rBottom >= 0 && cTop <= grid.Size.Cy {
                    for j := 0; j < len(row.Cells); j++ {
                        cell := row.Cells[j]
                        gridColumn := cell.GetColumn()
                        if !gridColumn.IsNotEmpty {
                            gridColumn = inGrid.Columns[j]
                        }
                        if gridColumn.Visible {
                            if gridColumn.Frozen{
                                cellWidth := gridColumn.Width
                                colSpan := cell.ColSpan
                                if colSpan > 1 {
                                    for n := 1; n < colSpan; n++ {
                                        spanColumn := inGrid.Columns[gridColumn.Index + n]
                                        if spanColumn.IsNotEmpty && spanColumn.Visible {
                                            cellWidth += spanColumn.Width
                                        }
                                    }
                                }
                                cellHeight := inGrid.RowHeight
                                rowSpan := cell.RowSpan
                                if rowSpan > 1 {
                                    for n := 1; n < rowSpan; n++ {
                                        spanRow := inGrid.Rows[i + n]
                                        if spanRow.IsNotEmpty && spanRow.Visible {
                                            cellHeight += inGrid.RowHeight
                                        }
                                    }
                                }
                                cRect := CreateRect(gridColumn.Bounds.Left - grid.ScrollH, rTop, gridColumn.Bounds.Left + cellWidth - grid.ScrollH, rTop + cellHeight)
                                if cRect.Right >= 0 && cRect.Left < grid.Size.Cx {
                                    if paint.OnPaintGridCell != nil{
                                        paint.OnPaintGridCell(grid, row, gridColumn, cell, paint, cRect.Left, cRect.Top, cRect.Right, cRect.Bottom)
                                    }else{    
                                        DrawGridCell(grid, row, gridColumn, cell, paint, cRect.Left, cRect.Top, cRect.Right, cRect.Bottom)
                                    }
                                    if len(cell.View) > 0{
                                        cellView := cell.GetView()
                                        cellView.Visible = true
                                        cellView.Location = CreatePoint(cRect.Left + grid.ScrollH, cRect.Top + grid.ScrollV)
                                        cellView.Size = CreateSize(cRect.Right - cRect.Left, cRect.Bottom - cRect.Top)
                                    }
                                }
                            }
                        }
                    }
                }
                if cTop > grid.Size.Cy {
                    break
                }
                cTop += inGrid.RowHeight
            }
        }
    }
}

/*
* 绘制表格的滚动条
* grid:表格
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawGridScrollBar(grid *FCView, paint *FCPaint, clipRect FCRect) {
    inGrid := grid.GetGrid()    
    grid.HScrollIsVisible = false
    grid.VScrollIsVisible = false
    if inGrid.HeaderHeight > 0 && len(inGrid.Columns) > 0 {
        cLeft := -grid.ScrollH
        //绘制列
        for i := 0; i < len(inGrid.Columns); i++ {
            gridColumn := inGrid.Columns[i]
            if inGrid.Columns[i].Visible {
                if !gridColumn.Frozen {
                    if paint.OnPaintGridColumn != nil{
                        paint.OnPaintGridColumn(grid, inGrid.Columns[i], paint, cLeft, 0, cLeft + gridColumn.Width, inGrid.HeaderHeight)
                    }else{
                        DrawGridColumn(grid, inGrid.Columns[i], paint, cLeft, 0, cLeft + gridColumn.Width, inGrid.HeaderHeight)
                    }
                }
                cLeft += gridColumn.Width
            }
        }
        cLeft = 0
        for i := 0; i < len(inGrid.Columns); i++ {
            gridColumn := inGrid.Columns[i]
            if inGrid.Columns[i].Visible {
                if gridColumn.Frozen {
                    if paint.OnPaintGridColumn != nil{
                        paint.OnPaintGridColumn(grid, inGrid.Columns[i], paint, cLeft, 0, cLeft + gridColumn.Width, inGrid.HeaderHeight)
                    }else{
                        DrawGridColumn(grid, inGrid.Columns[i], paint, cLeft, 0, cLeft + gridColumn.Width, inGrid.HeaderHeight)
                    }
                }
                cLeft += gridColumn.Width
            }
        }
    }
    if grid.ShowHScrollBar {
        contentWidth := GetGridContentWidth(grid)
        if contentWidth > 0 && contentWidth > grid.Size.Cx {
            sLeft := grid.ScrollH / contentWidth * grid.Size.Cx
            sRight := (grid.ScrollH + grid.Size.Cx) / contentWidth * grid.Size.Cx
            if sRight - sLeft < grid.ScrollSize {
                sRight = sLeft + grid.ScrollSize
            }
            if paint.GetTouchMoveView() == grid && (grid.HoverScrollHButton || grid.DownScrollHButton){
                paint.FillRect(grid.ScrollBarHoveredColor, sLeft, grid.Size.Cy - grid.ScrollSize, sRight, grid.Size.Cy)
            } else {
                paint.FillRect(grid.ScrollBarColor, sLeft, grid.Size.Cy - grid.ScrollSize, sRight, grid.Size.Cy)
            }
            grid.HScrollIsVisible = true
        }
    }
    if grid.ShowVScrollBar {
        contentHeight := GetGridContentHeight(grid)
        if contentHeight > 0 && contentHeight > grid.Size.Cy - inGrid.HeaderHeight {
            sTop := inGrid.HeaderHeight + grid.ScrollV / contentHeight * (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)
            sBottom := sTop + ((grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)) / contentHeight * (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)
            if sBottom - sTop < grid.ScrollSize {
                sBottom = sTop + grid.ScrollSize
            }
            if paint.GetTouchMoveView() == grid && (grid.HoverScrollVButton || grid.DownScrollVButton) {
                paint.FillRect(grid.ScrollBarHoveredColor, grid.Size.Cx - grid.ScrollSize, sTop, grid.Size.Cx, sBottom)
            } else {
                paint.FillRect(grid.ScrollBarColor, grid.Size.Cx - grid.ScrollSize, sTop, grid.Size.Cx, sBottom)
            }
            grid.VScrollIsVisible = true
        }
    }
}

/*
* 获取内容的宽度
* grid:表格
*/
func GetGridContentWidth(grid *FCView)(float64) {
    inGrid := grid.GetGrid()    
    cWidth := 0.0
    if len(inGrid.Columns) > 0{
        for i := 0; i < len(inGrid.Columns); i++ {
            if inGrid.Columns[i].Visible {
                cWidth += inGrid.Columns[i].Width
            }
        }
    }
    return cWidth
}

/*
* 获取内容的高度
* grid:表格
*/
func GetGridContentHeight(grid *FCView)(float64) {
    inGrid := grid.GetGrid()    
    cHeight := 0.0
    if len(inGrid.Rows) > 0{
        for i := 0; i < len(inGrid.Rows); i++ {
            if inGrid.Rows[i].Visible {
                cHeight += inGrid.RowHeight
            }
        }
    }
    return cHeight
}

/*
* 表格的鼠标移动方法
* grid: 表格
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func TouchMoveGrid(grid *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint) {
    inGrid := grid.GetGrid()        
    grid.HoverScrollHButton = false
    grid.HoverScrollVButton = false
    mp := CreatePoint(firstPoint.X, firstPoint.Y)
    paint := grid.GetPaint()
    if firstTouch {
        if paint.ResizeColumnState != 0 {
            gridColumn := inGrid.Columns[paint.ResizeColumnIndex]
            newWidth := paint.ResizeColumnBeginWidth + (mp.X - grid.StartPoint.X)
            if newWidth > 10 {
                gridColumn.Width = newWidth
            }
            return
        }
        if grid.ShowHScrollBar || grid.ShowVScrollBar {
            if grid.DownScrollHButton {
                contentWidth := GetGridContentWidth(grid)
                subX := (mp.X - grid.StartPoint.X) / grid.Size.Cx * contentWidth
                newScrollH := grid.StartScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - grid.Size.Cx {
                    newScrollH = contentWidth - grid.Size.Cx
                }
                grid.ScrollH = newScrollH
                paint.CancelClick = true
                return
            } else if grid.DownScrollVButton {
                contentHeight := GetGridContentHeight(grid)
                subY := (mp.Y - grid.StartPoint.Y) / (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize) * contentHeight
                newScrollV := grid.StartScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize) {
                    newScrollV = contentHeight - (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)
                }
                grid.ScrollV = newScrollV
                paint.CancelClick = true
                return
            }
        }
        if grid.AllowDragScroll {
            contentWidth := GetGridContentWidth(grid)
            if contentWidth > grid.Size.Cx - grid.ScrollSize {
                subX := grid.StartPoint.X - mp.X
                newScrollH := grid.StartScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - grid.Size.Cx{
                    newScrollH = contentWidth - grid.Size.Cx
                }
                grid.ScrollH = newScrollH
                if subX > 5 || subX < -5 {
                    paint.CancelClick = true
                }
            }
            contentHeight := GetGridContentHeight(grid)
            if contentHeight > grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize {
                subY := grid.StartPoint.Y - mp.Y
                newScrollV := grid.StartScrollV + subY
                if newScrollV < 0{
                    newScrollV = 0
                } else if newScrollV > contentHeight - (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize) {
                    newScrollV = contentHeight - (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)
                }
                grid.ScrollV = newScrollV
                if subY > 5 || subY < -5 {
                    paint.CancelClick = true
                }
            }
        }
    } else {
        if grid.ShowHScrollBar {
            contentWidth := GetGridContentWidth(grid)
            if contentWidth > 0 && contentWidth > grid.Size.Cx - grid.ScrollSize {
                sLeft := grid.ScrollH / contentWidth * grid.Size.Cx
                sRight := (grid.ScrollH + grid.Size.Cx) / contentWidth * grid.Size.Cx
                if sRight - sLeft < grid.ScrollSize {
                    sRight = sLeft + grid.ScrollSize
                }
                if mp.X >= sLeft && mp.X <= sRight && mp.Y >= grid.Size.Cy - grid.ScrollSize && mp.Y <= grid.Size.Cy {
                    grid.HoverScrollHButton = true
                    return
                } else {
                    grid.HoverScrollHButton = false
                }
            }
        }
        if grid.ShowVScrollBar {
            contentHeight := GetGridContentHeight(grid)
            if contentHeight > 0 && contentHeight > grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize {
                sTop := inGrid.HeaderHeight + grid.ScrollV / contentHeight * (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)
                sBottom := inGrid.HeaderHeight + (grid.ScrollV + (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)) / contentHeight * (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)
                if sBottom - sTop < grid.ScrollSize {
                    sBottom = sTop + grid.ScrollSize
                }
                if mp.X >= grid.Size.Cx - grid.ScrollSize && mp.X <= grid.Size.Cx && mp.Y >= sTop && mp.Y <= sBottom {
                    grid.HoverScrollVButton = true
                    return
                } else {
                    grid.HoverScrollVButton = false
                }
            }
        }
    }
}


/*
* 表格的鼠标按下方法
* grid: 表格
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func TouchDownGrid(grid *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int) {
    inGrid := grid.GetGrid()        
    mp := CreatePoint(firstPoint.X, firstPoint.Y)
    grid.StartPoint = mp
    grid.DownScrollHButton = false
    grid.DownScrollVButton = false
    grid.HoverScrollHButton = false
    grid.HoverScrollVButton = false
    if grid.ShowHScrollBar{
        contentWidth := GetGridContentWidth(grid)
        if contentWidth > 0 && contentWidth > grid.Size.Cx - grid.ScrollSize{
            sLeft := grid.ScrollH / contentWidth * grid.Size.Cx
            sRight := (grid.ScrollH + grid.Size.Cx) / contentWidth * grid.Size.Cx
            if sRight - sLeft < grid.ScrollSize {
                sRight = sLeft + grid.ScrollSize
            }
            if mp.X >= sLeft && mp.X <= sRight && mp.Y >= grid.Size.Cy - grid.ScrollSize && mp.Y <= grid.Size.Cy{
                grid.DownScrollHButton = true
                grid.StartScrollH = grid.ScrollH
                return
            }
        }
    }
    if grid.ShowVScrollBar {
        contentHeight := GetGridContentHeight(grid)
        if contentHeight > 0 && contentHeight > grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize {
            sTop := inGrid.HeaderHeight + grid.ScrollV / contentHeight * (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)
            sBottom := inGrid.HeaderHeight + (grid.ScrollV + (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)) / contentHeight * (grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize)
            if sBottom - sTop < grid.ScrollSize {
                sBottom = sTop + grid.ScrollSize
            }
            if mp.X >= grid.Size.Cx - grid.ScrollSize && mp.X <= grid.Size.Cx && mp.Y >= sTop && mp.Y <= sBottom {
                grid.DownScrollVButton = true
                grid.StartScrollV = grid.ScrollV
                return
            }
        }
    }
    if grid.AllowDragScroll {
        grid.StartScrollH = grid.ScrollH
        grid.StartScrollV = grid.ScrollV
    }
    colLeft := 0.0
    if len(inGrid.Columns) > 0{
        for i := 0; i < len(inGrid.Columns); i++ {
            colRect := CreateRect(colLeft, 0, colLeft + inGrid.Columns[i].Width, inGrid.HeaderHeight)
            inGrid.Columns[i].Bounds = colRect
            inGrid.Columns[i].Index = i
            colLeft += inGrid.Columns[i].Width
        }
    }
    paint := grid.GetPaint()
    paint.ResizeColumnState = 0
    paint.ResizeColumnBeginWidth = 0
    if (inGrid.HeaderHeight > 0 && mp.Y <= inGrid.HeaderHeight && len(inGrid.Columns) > 0) {
        //绘制列
        for i := 0; i < len(inGrid.Columns); i++ {
            gridColumn := inGrid.Columns[i]
            if gridColumn.Visible {
                bounds := gridColumn.Bounds
                if mp.X >= bounds.Left - grid.ScrollH && mp.X <= bounds.Right - grid.ScrollH {
                    if gridColumn.Index > 0 && mp.X < bounds.Left + 5 - grid.ScrollH {
                        paint.ResizeColumnState = 1
                        paint.ResizeColumnBeginWidth = inGrid.Columns[gridColumn.Index - 1].Bounds.Right - inGrid.Columns[gridColumn.Index - 1].Bounds.Left
                        paint.ResizeColumnIndex = gridColumn.Index - 1
                        return
                    }else if mp.X > bounds.Right - 5 - grid.ScrollH{
                        paint.ResizeColumnState = 2
                        paint.ResizeColumnBeginWidth = bounds.Right - bounds.Left
                        paint.ResizeColumnIndex = gridColumn.Index
                        return
                    }
                    break
                }
            }
        }
    }
    
    cTop := -grid.ScrollV + inGrid.HeaderHeight
    //绘制行
    colLeft = 0.0
    if len(inGrid.Columns) > 0{
        for i := 0; i < len(inGrid.Columns); i++ {
            colRect := CreateRect(colLeft, 0, colLeft + inGrid.Columns[i].Width, inGrid.HeaderHeight)
            inGrid.Columns[i].Bounds = colRect
            inGrid.Columns[i].Index = i
            colLeft += inGrid.Columns[i].Width
        }
    }
    //判断列头
	if inGrid.HeaderHeight > 0 && firstPoint.Y <= inGrid.HeaderHeight{
        cLeft := 0.0
		for i := 0; i < len(inGrid.Columns); i++ {
            gridColumn := inGrid.Columns[i]
			if gridColumn.Visible{
				if gridColumn.Frozen{
					if firstPoint.X >= cLeft && firstPoint.X <= cLeft + gridColumn.Width{
                        for j := 0; j < len(inGrid.Columns); j++{
							tColumn := inGrid.Columns[j]
							if tColumn == gridColumn {
								if tColumn.AllowSort {
									if (tColumn.Sort == "none" || tColumn.Sort == "desc") {
										tColumn.Sort = "asc"
                                        for r := 0; r < len(inGrid.Rows); r++{
                                            inGrid.Rows[r].SortColIndex = j
                                        }
                                        sort.Sort(SortGridRowAsc(inGrid.Rows))
									} else {
										tColumn.Sort = "desc"
                                        for r := 0; r < len(inGrid.Rows); r++{
                                            inGrid.Rows[r].SortColIndex = j
                                        }
                                        sort.Sort(SortGridRowDesc(inGrid.Rows))
									}
								} else {
									tColumn.Sort = "none"
								}
							} else {
								tColumn.Sort = "none"
							}
						}
						if grid.GetPaint().OnClickGridColumn != nil{
							grid.GetPaint().OnClickGridColumn(grid, gridColumn, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                        }
						return
                    }
                }
				cLeft += gridColumn.Width
            }
        }
		cLeft = -grid.ScrollH
        for i := 0; i < len(inGrid.Columns); i++ {
            gridColumn := inGrid.Columns[i]
			if gridColumn.Visible{
				if !gridColumn.Frozen{
					if firstPoint.X >= cLeft && firstPoint.X <= cLeft + gridColumn.Width{
                        for j := 0; j < len(inGrid.Columns); j++{
							tColumn := inGrid.Columns[j]
							if tColumn == gridColumn {
								if tColumn.AllowSort {
									if (tColumn.Sort == "none" || tColumn.Sort == "desc") {
										tColumn.Sort = "asc"
                                        for r := 0; r < len(inGrid.Rows); r++{
                                            inGrid.Rows[r].SortColIndex = j
                                        }
                                        sort.Sort(SortGridRowAsc(inGrid.Rows))
									} else {
										tColumn.Sort = "desc"
                                        for r := 0; r < len(inGrid.Rows); r++{
                                            inGrid.Rows[r].SortColIndex = j
                                        }
                                        sort.Sort(SortGridRowDesc(inGrid.Rows))
									}
								} else {
									tColumn.Sort = "none"
								}
							} else {
								tColumn.Sort = "none"
							}
						}
						if grid.GetPaint().OnClickGridColumn != nil{
							grid.GetPaint().OnClickGridColumn(grid, gridColumn, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                        }
						return
                    }
                }
				cLeft += gridColumn.Width
            }
        }
    }
    if len(inGrid.Rows) > 0{
        for i := 0; i < len(inGrid.Rows); i++ {
            row := inGrid.Rows[i]
            if row.Visible {
                rTop := cTop
                rBottom := cTop + inGrid.RowHeight
                if rBottom >= 0 && cTop <= grid.Size.Cy {
                    for j := 0; j < len(row.Cells); j++ {
                        cell := row.Cells[j]
                        gridColumn := cell.GetColumn()
                        if !gridColumn.IsNotEmpty {
                            gridColumn = inGrid.Columns[j]
                        }
                        if gridColumn.Visible {
                            if gridColumn.Frozen {
                                cellWidth := gridColumn.Width
                                colSpan := cell.ColSpan
                                if colSpan > 1 {
                                    for n := 1; n < colSpan; n++ {
                                        spanColumn := inGrid.Columns[gridColumn.Index + n]
                                        if spanColumn.IsNotEmpty && spanColumn.Visible{
                                            cellWidth += spanColumn.Width
                                        }
                                    }
                                }
                                cellHeight := inGrid.RowHeight
                                rowSpan := cell.RowSpan
                                if rowSpan > 1 {
                                    for n := 1; 1 < rowSpan; n++ {
                                        spanRow := inGrid.Rows[i + n]
                                        if spanRow.IsNotEmpty && spanRow.Visible {
                                            cellHeight += inGrid.RowHeight
                                        }
                                    }
                                }

                                cRect := CreateRect(gridColumn.Bounds.Left, rTop, gridColumn.Bounds.Left + cellWidth, rTop + cellHeight)
                                if cRect.Right >= 0 && cRect.Left < grid.Size.Cx {
                                    if firstPoint.X >= cRect.Left && firstPoint.X <= cRect.Right && firstPoint.Y >= cRect.Top && firstPoint.Y <= cRect.Bottom {
                                        for r := 0; r < len(inGrid.Rows); r++ {
                                            subRow := inGrid.Rows[r]
                                            if subRow == row {
                                                subRow.Selected = true
                                            } else {
                                                subRow.Selected = false
                                            }
                                        }
                                        if grid.GetPaint().OnClickGridCell != nil{
                                            grid.GetPaint().OnClickGridCell(grid, row, gridColumn, cell, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                                        }
                                        return
                                    }
                                }
                            }
                        }
                    }
                }
                if rBottom >= 0 && cTop <= grid.Size.Cy {
                     for j := 0; j < len(row.Cells); j++ {
                        cell := row.Cells[j]
                        gridColumn := cell.GetColumn()
                        if !gridColumn.IsNotEmpty {
                            gridColumn = inGrid.Columns[j]
                        }
                        if gridColumn.Visible {
                            if !gridColumn.Frozen {
                                cellWidth := gridColumn.Width
                                colSpan := cell.ColSpan
                                if colSpan > 1 {
                                    for n := 1; n < colSpan; n++ {
                                        spanColumn := inGrid.Columns[gridColumn.Index + n]
                                        if spanColumn.IsNotEmpty && spanColumn.Visible{
                                            cellWidth += spanColumn.Width
                                        }
                                    }
                                }
                                cellHeight := inGrid.RowHeight
                                rowSpan := cell.RowSpan
                                if rowSpan > 1 {
                                    for n := 1; 1 < rowSpan; n++ {
                                        spanRow := inGrid.Rows[i + n]
                                        if spanRow.IsNotEmpty && spanRow.Visible {
                                            cellHeight += inGrid.RowHeight
                                        }
                                    }
                                }

                                cRect := CreateRect(gridColumn.Bounds.Left - grid.ScrollH, rTop, gridColumn.Bounds.Left + cellWidth - grid.ScrollH, rTop + cellHeight)
                                if cRect.Right >= 0 && cRect.Left < grid.Size.Cx {
                                    if firstPoint.X >= cRect.Left && firstPoint.X <= cRect.Right && firstPoint.Y >= cRect.Top && firstPoint.Y <= cRect.Bottom {
                                        for r := 0; r < len(inGrid.Rows); r++ {
                                            subRow := inGrid.Rows[r]
                                            if subRow == row {
                                                subRow.Selected = true
                                            } else {
                                                subRow.Selected = false
                                            }
                                        }
                                        if grid.GetPaint().OnClickGridCell != nil{
                                            grid.GetPaint().OnClickGridCell(grid, row, gridColumn, cell, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                                        }
                                        return
                                    }
                                }
                            }
                        }
                    }
                }
                if cTop > grid.Size.Cy {
                    break
                }
                cTop += inGrid.RowHeight
            }
        }
    }
}

type SortGridRowAsc []*FCGridRow
func (a SortGridRowAsc) Len() int  { return len(a) }
func (a SortGridRowAsc) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a SortGridRowAsc) Less(i, j int) bool{
    leftCell := a[i].Cells[a[i].SortColIndex]
    rightCell :=  a[j].Cells[a[j].SortColIndex]
    leftColumn := leftCell.GetColumn()
    if(leftColumn.ColType == "double"){
        leftValue := ConvertToFloat64(leftCell.Value)
        rightValue := ConvertToFloat64(rightCell.Value)
        if(rightValue > leftValue){
            return true;
        }else{
            return false;
        }
    }else if(leftColumn.ColType == "int"){
        leftValue := ConvertToInt(leftCell.Value)
        rightValue := ConvertToInt(rightCell.Value)
        if(rightValue > leftValue){
            return true;
        }else{
            return false;
        }
    }else if(leftColumn.ColType == "bool"){
        leftValue := 1
        rightValue := 1
        if(leftCell.Value == "false"){
            leftValue = 0
        }
        if(rightCell.Value == "false"){
            rightValue =  0
        }
        if(rightValue > leftValue){
            return true;
        }else{
            return false;
        }
    }else{
        return rightCell.Value > leftCell.Value
    }
}

type SortGridRowDesc []*FCGridRow
func (a SortGridRowDesc) Len() int  { return len(a) }
func (a SortGridRowDesc) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func (a SortGridRowDesc) Less(i, j int) bool{
    leftCell := a[i].Cells[a[i].SortColIndex]
    rightCell :=  a[j].Cells[a[j].SortColIndex]
     leftColumn := leftCell.GetColumn()
    if(leftColumn.ColType == "double"){
        leftValue := ConvertToFloat64(leftCell.Value)
        rightValue := ConvertToFloat64(rightCell.Value)
        if(rightValue < leftValue){
            return true;
        }else{
            return false;
        }
    }else if(leftColumn.ColType == "int"){
        leftValue := ConvertToInt(leftCell.Value)
        rightValue := ConvertToInt(rightCell.Value)
        if(rightValue < leftValue){
            return true;
        }else{
            return false;
        }
    }else if(leftColumn.ColType == "bool"){
        leftValue := 1
        rightValue := 1
        if(leftCell.Value == "false"){
            leftValue = 0
        }
        if(rightCell.Value == "false"){
            rightValue =  0
        }
        if(rightValue < leftValue){
            return true;
        }else{
            return false;
        }
    }else{
        return rightCell.Value < leftCell.Value
    }
}

/*
* 表格的鼠标抬起方法
* grid: 表格
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func TouchUpGrid(grid *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int) {
    inGrid := grid.GetGrid()        
    paint := grid.GetPaint()
    grid.HoverScrollHButton = false
    grid.HoverScrollVButton = false
    grid.DownScrollHButton = false
    grid.DownScrollVButton = false
}

/*
* 表格的鼠标滚轮方法
* grid:表格
* delta:滚轮值
*/
func TouchWheelGrid(grid *FCView, delta int) {
    inGrid := grid.GetGrid()        
    oldScrollV := grid.ScrollV
    if delta > 0 {
        oldScrollV -= inGrid.RowHeight
    } else if delta < 0 {
        oldScrollV += inGrid.RowHeight
    }
    contentHeight := GetGridContentHeight(grid)
    if contentHeight < grid.Size.Cy - inGrid.HeaderHeight - grid.ScrollSize {
        grid.ScrollV = 0
    } else {
        if oldScrollV < 0 {
            oldScrollV = 0
        } else if oldScrollV > contentHeight - grid.Size.Cy + inGrid.HeaderHeight + grid.ScrollSize{
            oldScrollV = contentHeight - grid.Size.Cy + inGrid.HeaderHeight + grid.ScrollSize
        }
        grid.ScrollV = oldScrollV
    }
}

/*
* 重置布局图层
* layout:布局层
*/
func ResetLayoutDiv(layout *FCView) {
    inLayout := layout.GetLayoutDiv()
    padding := CreatePadding(0, 0, 0, 0)
    if layout.Padding.IsNotEmpty{
        padding = layout.Padding
    }
    vPos := 0
    left := padding.Left
    top := padding.Top
    width := layout.Size.Cx - padding.Left - padding.Right
    height := layout.Size.Cy - padding.Top - padding.Bottom
    if len(layout.Views) > 0{
        for i := 0; i < len(layout.Views); i++ {
            view := layout.Views[i]
            if view.Visible {
                size := view.Size
                margin := CreatePadding(0, 0, 0, 0)
                if view.Margin.IsNotEmpty{
                    margin = view.Margin
                }
                cLeft := view.Location.X
                cTop := view.Location.Y
                cWidth := size.Cx
                cHeight := size.Cy
                nLeft := cLeft
                nTop := cTop
                nWidth := cWidth
                nHeight := cHeight
                if inLayout.LayoutStyle == "bottomtotop" {
                    if i == 0{
                        top = height - padding.Top
                    }
                    lWidth := 0.0
                    if inLayout.AutoWrap {
                        lWidth = size.Cx
                        lTop := top - margin.Top - cHeight - margin.Bottom
                        if lTop < padding.Top {
                            if (vPos != 0) {
                                left += cWidth + margin.Left
                            }
                            top = height - padding.Top
                        }
                    }else {
                        lWidth = width - margin.Left - margin.Right
                    }
                    top -= cHeight + margin.Bottom
                    nLeft = left + margin.Left
                    nWidth = lWidth
                    nTop = top
                } else if inLayout.LayoutStyle == "lefttoright" {
                    lHeight := 0.0
                    if inLayout.AutoWrap {
                        lHeight = size.Cy
                        lRight := left + margin.Left + cWidth + margin.Right
                        if lRight > width {
                            left = padding.Left
                            if vPos != 0 {
                                top += cHeight + margin.Top
                            }
                        }
                    }else {
                        lHeight = height - margin.Top - margin.Bottom
                    }
                    left += margin.Left
                    nLeft = left
                    nTop = top + margin.Top
                    nHeight = lHeight
                    left += cWidth + margin.Right
                } else if inLayout.LayoutStyle == "righttoleft" {
                    if i == 0 {
                        left = width - padding.Left
                    }
                    lHeight := 0.0
                    if inLayout.AutoWrap {
                        lHeight = size.Cy
                        lLeft := left - margin.Left - cWidth - margin.Right
                        if lLeft < padding.Left {
                            left = width - padding.Left
                            if vPos != 0 {
                                top += cHeight + margin.Top
                            }
                        }
                    }else {
                        lHeight = height - margin.Top - margin.Bottom
                    }
                    left -= cWidth + margin.Left
                    nLeft = left
                    nTop = top + margin.Top
                    nHeight = lHeight
                } else if inLayout.LayoutStyle == "toptobottom" {
                    lWidth := 0.0
                    if inLayout.AutoWrap {
                        lWidth = size.Cx
                        lBottom := top + margin.Top + cHeight + margin.Bottom
                        if lBottom > height{
                            if vPos != 0 {
                                left += cWidth + margin.Left + margin.Right
                            }
                            top = padding.Top
                        }
                    }else {
                        lWidth = width - margin.Left - margin.Right
                    }
                    top += margin.Top
                    nTop = top
                    nLeft = left + margin.Left
                    nWidth = lWidth
                    top += cHeight + margin.Bottom
                }
                if cLeft != nLeft || cTop != nTop || cWidth != nWidth || cHeight != nHeight {
                    view.Location = CreatePoint(nLeft, nTop)
                    view.Size = CreateSize(nWidth, nHeight)
                    //reset = true
                }
                vPos += 1
            }
        }
    }
}

/*
* 更新页的布局
* tabView:多页夹
* tabPage:页
* left:左侧坐标
* top:上方坐标
* width:宽度
* height:高度
* tw:页头按钮的宽度
* th:页头按钮的高度
*/
func UpdataPageLayout(tabView *FCView, tabPage *FCView, left float64, top float64, width float64, height float64, tw float64, th float64) {
    newBounds := CreateRect(0, 0, 0, 0)
    inTabPage := tabPage.GetTabPage()
    inTabView := tabView.GetTabView()
    headerButton := inTabPage.GetHeaderButton()
    if inTabView.Layout == "bottom" {
        newBounds.Left = 0
        newBounds.Top = 0
        newBounds.Right = width
        newBounds.Bottom = height - th
        headerButton.Location = CreatePoint(left, height - th)
    } else if inTabView.Layout == "left"{
        newBounds.Left = tw
        newBounds.Top = 0
        newBounds.Right = width
        newBounds.Bottom = height
        headerButton.Location = CreatePoint(0, top)
    } else if inTabView.Layout == "right" {
        newBounds.Left = 0
        newBounds.Top = 0
        newBounds.Right = width - tw
        newBounds.Bottom = height
        headerButton.Location = CreatePoint(width - tw, top)
    } else if inTabView.Layout == "top" {
        newBounds.Left = 0
        newBounds.Top = th
        newBounds.Right = width
        newBounds.Bottom = height
        headerButton.Location = CreatePoint(left, 0)
    }
    tabPage.Location = CreatePoint(newBounds.Left, newBounds.Top)
    tabPage.Size = CreateSize(newBounds.Right - newBounds.Left, newBounds.Bottom - newBounds.Top)
}

/*
* 更新多页夹的布局
* tabView:多页夹
*/
func UpdateTabLayout(tabView *FCView) {
    width := tabView.Size.Cx
    height := tabView.Size.Cy
    left := 0.0
    top := 0.0
    inTabView := tabView.GetTabView()
    if len(inTabView.TabPages) > 0{
        for i := 0; i < len(inTabView.TabPages); i++ {
            tabPage := inTabView.TabPages[i]
            inTabPage := tabPage.GetTabPage()
            headerButton := inTabPage.GetHeaderButton()
            if headerButton.Visible {
                tw := headerButton.Size.Cx
                th := headerButton.Size.Cy
                UpdataPageLayout(tabView, tabPage, left, top, width, height, tw, th)
                left += tw
                top += th
            } else {
                tabPage.Visible = false
            }
        }
    }
}

/*
* 重置分割线的布局
* split:分割视图
*/
func ResetSplitLayoutDiv(split *FCView){
    inSplit := split.GetSplitDiv()
    splitRect := CreateRect(0, 0, 0, 0)
    width := split.Size.Cx
    height := split.Size.Cy
    fRect := CreateRect(0, 0, 0, 0)
    sRect := CreateRect(0, 0, 0, 0)
    splitter := inSplit.GetSplitter()
    splitterSize := CreateSize(0, 0)
    if splitter.Visible {
        splitterSize.Cx = splitter.Size.Cx
        splitterSize.Cy = splitter.Size.Cy
    }
    layoutStyle := inSplit.LayoutStyle
    if layoutStyle == "bottomtotop" {
        if inSplit.SplitMode == "absolutesize" || inSplit.OldSize.Cy == 0 {
            splitRect.Left = 0
            splitRect.Top = height - (inSplit.OldSize.Cy - splitter.Location.Y)
            splitRect.Right = width
            splitRect.Bottom = splitRect.Top + splitterSize.Cy
        }else if inSplit.SplitMode == "percentsize" {
            splitRect.Left = 0
            if inSplit.SplitPercent == -1 {
                inSplit.SplitPercent = splitter.Location.Y / inSplit.OldSize.Cy
            }
            splitRect.Top = height * inSplit.SplitPercent
            splitRect.Right = width
            splitRect.Bottom = splitRect.Top + splitterSize.Cy
        }
        fRect.Left = 0
        fRect.Top = splitRect.Bottom
        fRect.Right = width
        fRect.Bottom = height
        sRect.Left = 0
        sRect.Top = 0
        sRect.Right = width
        sRect.Bottom = splitRect.Top
    }else if layoutStyle == "lefttoright" {
        if inSplit.SplitMode == "absolutesize" || inSplit.OldSize.Cx == 0 {
            splitRect.Left = splitter.Location.X
            splitRect.Top = 0
            splitRect.Right = splitRect.Left + splitterSize.Cx
            splitRect.Bottom = height
        }else if inSplit.SplitMode == "percentsize" {
            if inSplit.SplitPercent == -1 {
                inSplit.SplitPercent = splitter.Location.X / inSplit.OldSize.Cx
            }
            splitRect.Left = width * inSplit.SplitPercent
            splitRect.Top = 0
            splitRect.Right = splitRect.Left + splitterSize.Cx
            splitRect.Bottom = height
        }
        fRect.Left = 0
        fRect.Top = 0
        fRect.Right = splitRect.Left
        fRect.Bottom = height
        sRect.Left = splitRect.Right
        sRect.Top = 0
        sRect.Right = width
        sRect.Bottom = height
    }else if layoutStyle == "righttoleft" {
        if inSplit.SplitMode == "absolutesize" || inSplit.OldSize.Cx == 0 {
            splitRect.Left = width - (inSplit.OldSize.Cx - splitter.Location.X)
            splitRect.Top = 0
            splitRect.Right = splitRect.Left + splitterSize.Cx
            splitRect.Bottom = height
        }else if inSplit.SplitMode == "percentsize" {
            if inSplit.SplitPercent == -1 {
                inSplit.SplitPercent = splitter.Location.X / inSplit.OldSize.Cx
            }
            splitRect.Left = width * inSplit.SplitPercent
            splitRect.Top = 0
            splitRect.Right = splitRect.Left + splitterSize.Cx
            splitRect.Bottom = height
        }
        fRect.Left = splitRect.Right
        fRect.Top = 0
        fRect.Right = width
        fRect.Bottom = height
        sRect.Left = 0
        sRect.Top = 0
        sRect.Right = splitRect.Left
        sRect.Bottom = height
    }else if layoutStyle == "toptobottom" {
        if inSplit.SplitMode == "absolutesize" || inSplit.OldSize.Cy == 0 {
            splitRect.Left = 0
            splitRect.Top = splitter.Location.Y
            splitRect.Right = width
            splitRect.Bottom = splitRect.Top + splitterSize.Cy
        }else if inSplit.SplitMode == "percentsize" {
            splitRect.Left = 0
            if inSplit.SplitPercent == -1{
                inSplit.SplitPercent = splitter.Location.Y / inSplit.OldSize.Cy
            }
            splitRect.Top = height * inSplit.SplitPercent
            splitRect.Right = width
            splitRect.Bottom = splitRect.Top + splitterSize.Cy
        }
        fRect.Left = 0
        fRect.Top = 0
        fRect.Right = width
        fRect.Bottom = splitRect.Top
        sRect.Left = 0
        sRect.Top = splitRect.Bottom
        sRect.Right = width
        sRect.Bottom = height
    }
    if splitter.Visible {
        spRect := CreateRect(splitter.Location.X, splitter.Location.Y, splitter.Location.X + splitter.Size.Cx, splitter.Location.Y + splitter.Size.Cy)
        if spRect.Left != splitRect.Left || spRect.Top != splitRect.Top || spRect.Right != splitRect.Right || spRect.Bottom != splitRect.Bottom {
            splitter.Location = CreatePoint(splitRect.Left, splitRect.Top)
            splitter.Size = CreateSize(splitRect.Right - splitRect.Left, splitRect.Bottom - splitRect.Top)
            //reset = true
        }
    }
    FirstView := inSplit.GetFirstView()
    fcRect := CreateRect(FirstView.Location.X, FirstView.Location.Y, FirstView.Location.X + FirstView.Size.Cx, FirstView.Location.Y + FirstView.Size.Cy)
    if fcRect.Left != fRect.Left || fcRect.Top != fRect.Top || fcRect.Right != fRect.Right || fcRect.Bottom != fRect.Bottom {
        //reset = true
        FirstView.Location = CreatePoint(fRect.Left, fRect.Top)
        FirstView.Size = CreateSize(fRect.Right - fRect.Left, fRect.Bottom - fRect.Top)
    }
    SecondView := inSplit.GetSecondView()
    scRect := CreateRect(SecondView.Location.X, SecondView.Location.Y, SecondView.Location.X + SecondView.Size.Cx, SecondView.Location.Y + SecondView.Size.Cy)
    if scRect.Left != sRect.Left || scRect.Top != sRect.Top || scRect.Right != sRect.Right || scRect.Bottom != sRect.Bottom{
        //reset = true
        SecondView.Location = CreatePoint(sRect.Left, sRect.Top)
        SecondView.Size = CreateSize(sRect.Right - sRect.Left, sRect.Bottom - sRect.Top)
    }
    inSplit.OldSize = CreateSize(width, height)
}

/*
* 添加页
* tabView:多页夹
* tabPage:页
* tabButton:页头按钮
*/
func AddTabPage(tabView *FCView, tabPage *FCView, tabButton *FCView) {
    inTabPage := tabPage.GetTabPage()
    inTabView := tabView.GetTabView()
    inTabPage.SetHeaderButton(tabButton)
    tabPage.SetParent(tabView)
    tabPage.SetPaint(tabView.GetPaint())
    tabButton.SetParent(tabView)
    tabButton.SetPaint(tabView.GetPaint())
    inTabView.TabPages = append(inTabView.TabPages, tabPage)
    tabView.Views = append(tabView.Views, tabPage)
    tabView.Views = append(tabView.Views, tabButton)
}

/*
* 移除页
* tabView:多页夹
* tabPage:页
*/
func RemoveTabPage(tabView *FCView, tabPage *FCView) {
    inTabPage := tabPage.GetTabPage()
    inTabView := tabView.GetTabView()
    headerButton := inTabPage.GetHeaderButton()
    if len(tabView.Views) > 0{
        for i := 0; i < len(tabView.Views); i++ {
            if tabView.Views[i] == headerButton {
                tabView.Views = append(tabView.Views[:i], tabView.Views[i + 1:]...)
                break
            }
        }
        for i := 0; i < len(tabView.Views); i++ {
            if tabView.Views[i] == tabPage {
                tabView.Views = append(tabView.Views[:i], tabView.Views[i + 1:]...)
                break
            }
        }
        for i := 0; i < len(tabView.Views); i++ {
            if inTabView.TabPages[i] == tabPage {
                tabView.Views = append(tabView.Views[:i], tabView.Views[i + 1:]...)
                break
            }
        }
    }
}

/*
* 选中页
* tabView:多页夹
* tabPage:页
*/
func SelectTabPage(tabView *FCView, tabPage *FCView) {
    inTabView := tabView.GetTabView()
    if len(tabView.Views) > 0{
        for i := 0; i < len(inTabView.TabPages); i++ {
            tp := inTabView.TabPages[i]
            if tp == tabPage {
                tp.Visible = true
            } else {
                tp.Visible = false
            }
        }
    }
    UpdateTabLayout(tabView)
}

/*
* 重绘多页加
* tabView:多页夹
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawTabViewBorder(tabView *FCView, paint *FCPaint, clipRect FCRect) {
    inTabView := tabView.GetTabView()
    if inTabView.UnderLineColor != "none" {
        if len(tabView.Views) > 0{
            for i := 0; i < len(inTabView.TabPages); i++ {
                tp := inTabView.TabPages[i]
                if tp.Visible {
                    inTabPage := tp.GetTabPage()
                    headerButton := inTabPage.GetHeaderButton()
                    location := CreatePoint(headerButton.Location.X, headerButton.Location.Y)
                    size := headerButton.Size
                    if inTabView.UseAnimation {
                        if inTabView.UnderPoint.X != 0 && inTabView.UnderPoint.Y != 0 {
                            location.X = inTabView.UnderPoint.X
                            location.Y = inTabView.UnderPoint.Y
                        }
                    }
                    if inTabView.Layout == "bottom" {
                        paint.FillRect(inTabView.UnderLineColor, location.X, location.Y, location.X + size.Cx, location.Y + inTabView.UnderLineSize)
                    } else if inTabView.Layout == "left" {
                        paint.FillRect(inTabView.UnderLineColor, location.X + size.Cx - inTabView.UnderLineSize, location.Y, location.X + size.Cx, location.Y + size.Cy)
                    } else if inTabView.Layout == "top" {
                        paint.FillRect(inTabView.UnderLineColor, location.X, location.Y + size.Cy - inTabView.UnderLineSize, location.X + size.Cx, location.Y + size.Cy)
                    }else if inTabView.Layout == "right"{
                        paint.FillRect(inTabView.UnderLineColor, location.X, location.Y, location.X + inTabView.UnderLineSize, location.Y + size.Cy)
                    }
                    break
                }
            }
        }
    }
}

/*
* 获取总的偏移量
* node:树节点
*/
func GetTotalIndent(node *FCTreeNode)(float64) {
    if node.GetParentNode().IsNotEmpty {
        return node.Indent + GetTotalIndent(node.GetParentNode())
    } else {
        return node.Indent
    }
}

/*
* 绘制单元格
* tree:树
* row:行
* column:列
* node:节点
* paint:绘图对象
* left:左侧坐标
* top:上方坐标
* right:右侧坐标
* bottom:下方坐标
*/
func DrawTreeNode(tree *FCView, row *FCTreeRow, column *FCTreeColumn, node *FCTreeNode, paint *FCPaint, left float64, top float64, right float64, bottom float64) {
    inTree := tree.GetTree()
    if node.BackColor != "none" {
        paint.FillRect(node.BackColor, left, top, right, bottom)
    }
    if len(node.Value) > 0 {
        tSize := paint.TextSize(node.Value, node.Font)
        tLeft := left + 2 + GetTotalIndent(node)
        wLeft := tLeft
        cR := inTree.CheckBoxWidth / 3
        if inTree.ShowCheckBox {
            wLeft += inTree.CheckBoxWidth
            if node.Checked {
                paint.FillRect(node.TextColor, tLeft + (inTree.CheckBoxWidth - cR) / 2, top + (inTree.RowHeight - cR) / 2, tLeft + (inTree.CheckBoxWidth + cR) / 2, top + (inTree.RowHeight + cR) / 2)
            } else {
                paint.DrawRect(node.TextColor, 1, 0, tLeft + (inTree.CheckBoxWidth - cR) / 2, top + (inTree.RowHeight - cR) / 2, tLeft + (inTree.CheckBoxWidth + cR) / 2, top + (inTree.RowHeight + cR) / 2)
            }
        }
        if len(node.ChildNodes) > 0 {
            var drawPoints []FCPoint
            if node.Collapsed {
                drawPoints = append(drawPoints, CreatePoint(wLeft + (inTree.CollapsedWidth + cR) / 2, top + inTree.RowHeight / 2))
				drawPoints = append(drawPoints, CreatePoint(wLeft + (inTree.CollapsedWidth - cR) / 2, top + (inTree.RowHeight - cR) / 2))
				drawPoints = append(drawPoints, CreatePoint(wLeft + (inTree.CollapsedWidth - cR) / 2, top + (inTree.RowHeight + cR) / 2))
            } else {
                drawPoints = append(drawPoints, CreatePoint(wLeft + (inTree.CollapsedWidth - cR) / 2, top + (inTree.RowHeight - cR) / 2))
				drawPoints = append(drawPoints, CreatePoint(wLeft + (inTree.CollapsedWidth + cR) / 2, top + (inTree.RowHeight - cR) / 2))
				drawPoints = append(drawPoints, CreatePoint(wLeft + inTree.CollapsedWidth / 2, top + (inTree.RowHeight + cR) / 2))
            }
            paint.FillPolygon(node.TextColor, drawPoints)
            wLeft += inTree.CollapsedWidth
        }
        
        if tSize.Cx > column.Width{
            paint.DrawTextAutoEllipsis(node.Value, node.TextColor, node.Font, wLeft, top + inTree.RowHeight / 2 - tSize.Cy / 2, wLeft + column.Width, top + inTree.RowHeight / 2 - tSize.Cy / 2)
        } else {
            paint.DrawText(node.Value, node.TextColor, node.Font, wLeft, top + inTree.RowHeight / 2 - tSize.Cy / 2)
        }
    }
}

/*
* 绘制树
* tree:树
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawTree(tree *FCView, paint *FCPaint, clipRect FCRect) {
    inTree := tree.GetTree()
    cTop := -tree.ScrollV + inTree.HeaderHeight
    //绘制行
    colLeft := 0.0
    if len(inTree.Columns) > 0{
        for i := 0; i < len(inTree.Columns); i++ {
            if(len(inTree.Columns[i].WidthStr) > 0){
                newWidthStr := strings.Replace(inTree.Columns[i].WidthStr, "(", "", -1)
                inTree.Columns[i].Width = ConvertToFloat64(newWidthStr) * tree.Size.Cx / 100
            }
            colRect := CreateRect(colLeft, 0, colLeft + inTree.Columns[i].Width, inTree.HeaderHeight)
            inTree.Columns[i].Bounds = colRect
            inTree.Columns[i].Index = i
            colLeft += inTree.Columns[i].Width
        }
    }
    UpdateTreeRowIndex(tree)
    if len(inTree.Rows) > 0{
        for i := 0; i < len(inTree.Rows); i++ {
            row := inTree.Rows[i]
            if row.Visible {
                rTop := cTop
                rBottom := cTop + inTree.RowHeight
                if rBottom >= 0 && cTop <= tree.Size.Cy{
                    for j := 0; j < len(row.Cells); j++ {
                        node := row.Cells[j]
                        treeColumn := node.GetColumn()
                        if !treeColumn.IsNotEmpty {
                            treeColumn = inTree.Columns[j]
                        }
                        if treeColumn.Visible {
                            nodeWidth := treeColumn.Width
                            nodeHeight := inTree.RowHeight
                            cRect := CreateRect(treeColumn.Bounds.Left - tree.ScrollH, rTop, treeColumn.Bounds.Left + nodeWidth - tree.ScrollH, rTop + nodeHeight)
                            if cRect.Right >= 0 && cRect.Left < tree.Size.Cx {
                                if paint.OnPaintTreeNode != nil{
                                    paint.OnPaintTreeNode(tree, row, treeColumn, node, paint, cRect.Left, cRect.Top, cRect.Right, cRect.Bottom)
                                }else{
                                    DrawTreeNode(tree, row, treeColumn, node, paint, cRect.Left, cRect.Top, cRect.Right, cRect.Bottom)
                                }
                            }
                        }
                    }
                }
                if cTop > tree.Size.Cy {
                    break
                }
                cTop += inTree.RowHeight
            }
        }
    }
}

/*
* 绘制滚动条
* tree:树
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawTreeScrollBar(tree *FCView, paint *FCPaint, clipRect FCRect) {
    tree.HScrollIsVisible = false
    tree.VScrollIsVisible = false
    inTree := tree.GetTree()
    if tree.ShowHScrollBar {
        contentWidth := GetTreeContentWidth(tree)
        if contentWidth > 0 && contentWidth > tree.Size.Cx {
            sLeft := tree.ScrollH / contentWidth * tree.Size.Cx
            sRight := (tree.ScrollH + tree.Size.Cx) / contentWidth * tree.Size.Cx
            if sRight - sLeft < tree.ScrollSize {
                sRight = sLeft + tree.ScrollSize
            }
            if paint.GetTouchMoveView() == tree && (tree.HoverScrollHButton || tree.DownScrollHButton) {
                paint.FillRect(tree.ScrollBarHoveredColor, sLeft, tree.Size.Cy - tree.ScrollSize, sRight, tree.Size.Cy)
            }else {
                paint.FillRect(tree.ScrollBarColor, sLeft, tree.Size.Cy - tree.ScrollSize, sRight, tree.Size.Cy)
            }
            tree.HScrollIsVisible = true
        }
    }
    if tree.ShowVScrollBar{
        contentHeight := GetTreeContentHeight(tree)
        if contentHeight > 0 && contentHeight > tree.Size.Cy {
            sTop := inTree.HeaderHeight + tree.ScrollV / contentHeight * (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize)
            sBottom := sTop + ((tree.Size.Cy - inTree.HeaderHeight)) / contentHeight * (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize)
            if sBottom - sTop < tree.ScrollSize {
                sBottom = sTop + tree.ScrollSize
            }
            if paint.GetTouchMoveView() == tree && (tree.HoverScrollVButton || tree.DownScrollVButton) {
                paint.FillRect(tree.ScrollBarHoveredColor, tree.Size.Cx - tree.ScrollSize, sTop, tree.Size.Cx, sBottom)
            } else {
                paint.FillRect(tree.ScrollBarColor, tree.Size.Cx - tree.ScrollSize, sTop, tree.Size.Cx, sBottom)
            }
            tree.VScrollIsVisible = true
        }
    }
}

/*
* 获取内容的宽度
* tree:树
*/
func GetTreeContentWidth(tree *FCView)(float64){
    inTree := tree.GetTree()
    cWidth := 0.0
    if len(inTree.Columns) > 0{
        for i := 0; i < len(inTree.Columns); i++ {
            if inTree.Columns[i].Visible {
                cWidth += inTree.Columns[i].Width
            }
        }
    }
    return cWidth
}

/*
* 获取内容的高度
* tree:树
*/
func GetTreeContentHeight(tree *FCView)(float64){
    inTree := tree.GetTree()
    cHeight := 0.0
    if len(inTree.Rows) > 0{
        for i := 0; i < len(inTree.Rows); i++ {
            if inTree.Rows[i].Visible {
                cHeight += inTree.RowHeight
            }
        }
    }
    return cHeight
}

/*
* 树的鼠标移动方法
* tree: 树
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func TouchMoveTree(tree *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint) {
    inTree := tree.GetTree()
    tree.HoverScrollHButton = false
    tree.HoverScrollVButton = false
    mp := CreatePoint(firstPoint.X, firstPoint.Y)
    paint := tree.GetPaint()
    if firstTouch {
        if tree.ShowHScrollBar || tree.ShowVScrollBar {
            if (tree.DownScrollHButton) {
                contentWidth := GetTreeContentWidth(tree)
                subX := (mp.X - tree.StartPoint.X) / tree.Size.Cx * contentWidth
                newScrollH := tree.StartScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - tree.Size.Cx {
                    newScrollH = contentWidth - tree.Size.Cx
                }
                tree.ScrollH = newScrollH
                paint.CancelClick = true
                return
            } else if tree.DownScrollVButton {
                contentHeight := GetTreeContentHeight(tree)
                subY := (mp.Y - tree.StartPoint.Y) / (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize) * contentHeight
                newScrollV := tree.StartScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize) {
                    newScrollV = contentHeight - (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize)
                }
                tree.ScrollV = newScrollV
                paint.CancelClick = true
                return
            }
        }
        if tree.AllowDragScroll {
            contentWidth := GetTreeContentWidth(tree)
            if contentWidth > tree.Size.Cx {
                subX := tree.StartPoint.X - mp.X
                newScrollH := tree.StartScrollH + subX
                if newScrollH < 0 {
                    newScrollH = 0
                } else if newScrollH > contentWidth - tree.Size.Cx {
                    newScrollH = contentWidth - tree.Size.Cx
                }
                tree.ScrollH = newScrollH
                if subX > 5 || subX < -5 {
                    paint.CancelClick = true
                }
            }
            contentHeight := GetTreeContentHeight(tree)
            if contentHeight > tree.Size.Cy {
                subY := tree.StartPoint.Y - mp.Y
                newScrollV := tree.StartScrollV + subY
                if newScrollV < 0 {
                    newScrollV = 0
                } else if newScrollV > contentHeight - (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize) {
                    newScrollV = contentHeight - (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize)
                }
                tree.ScrollV = newScrollV
                if subY > 5 || subY < -5 {
                    paint.CancelClick = true
                }
            }
        }
    } else {
        if tree.ShowHScrollBar {
            contentWidth := GetTreeContentWidth(tree)
            if contentWidth > 0 && contentWidth > tree.Size.Cx {
                sLeft := tree.ScrollH / contentWidth * tree.Size.Cx
                sRight := (tree.ScrollH + tree.Size.Cx) / contentWidth * tree.Size.Cx
                if sRight - sLeft < tree.ScrollSize {
                    sRight = sLeft + tree.ScrollSize
                }
                if mp.X >= sLeft && mp.X <= sRight && mp.Y >= tree.Size.Cy - tree.ScrollSize && mp.Y <= tree.Size.Cy {
                    tree.HoverScrollHButton = true
                    return
                } else {
                    tree.HoverScrollHButton = false
                }
            }
        }
        if tree.ShowVScrollBar {
            contentHeight := GetTreeContentHeight(tree)
            if contentHeight > 0 && contentHeight > tree.Size.Cy{
                sTop := inTree.HeaderHeight + tree.ScrollV / contentHeight * (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize)
                sBottom := inTree.HeaderHeight + (tree.ScrollV + (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize)) / contentHeight * (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize)
                if sBottom - sTop < tree.ScrollSize {
                    sBottom = sTop + tree.ScrollSize
                }
                if mp.X >= tree.Size.Cx - tree.ScrollSize && mp.X <= tree.Size.Cx && mp.Y >= sTop && mp.Y <= sBottom {
                    tree.HoverScrollVButton = true
                    return
                } else {
                    tree.HoverScrollVButton = false
                }
            }
        }
    }
}

/*
* 树的鼠标按下方法
* tree: 树
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func TouchDownTree(tree *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int) {
    inTree := tree.GetTree()
    mp := CreatePoint(firstPoint.X, firstPoint.Y)
    tree.StartPoint = mp
    tree.DownScrollHButton = false
    tree.DownScrollVButton = false
    if tree.ShowHScrollBar {
        contentWidth := GetTreeContentWidth(tree)
        if contentWidth > 0 && contentWidth > tree.Size.Cx {
            sLeft := tree.ScrollH / contentWidth * tree.Size.Cx
            sRight := (tree.ScrollH + tree.Size.Cx) / contentWidth * tree.Size.Cx
            if sRight - sLeft < tree.ScrollSize {
                sRight = sLeft + tree.ScrollSize
            }
            if mp.X >= sLeft && mp.X <= sRight && mp.Y >= tree.Size.Cy - tree.ScrollSize && mp.Y <= tree.Size.Cy {
                tree.DownScrollHButton = true
                tree.StartScrollH = tree.ScrollH
                return
            }
        }
    }
    if tree.ShowVScrollBar {
        contentHeight := GetTreeContentHeight(tree)
        if contentHeight > 0 && contentHeight > tree.Size.Cy {
            sTop := inTree.HeaderHeight + tree.ScrollV / contentHeight * (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize)
            sBottom := inTree.HeaderHeight + (tree.ScrollV + (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize)) / contentHeight * (tree.Size.Cy - inTree.HeaderHeight - tree.ScrollSize)
            if sBottom - sTop < tree.ScrollSize {
                sBottom = sTop + tree.ScrollSize
            }
            if mp.X >= tree.Size.Cx - tree.ScrollSize && mp.X <= tree.Size.Cx && mp.Y >= sTop && mp.Y <= sBottom {
                tree.DownScrollVButton = true
                tree.StartScrollV = tree.ScrollV
                return
            }
        }
    }
    if tree.AllowDragScroll {
        tree.StartScrollH = tree.ScrollH
        tree.StartScrollV = tree.ScrollV
    }
    
    cLeft := -tree.ScrollH
    cTop := -tree.ScrollV + inTree.HeaderHeight
    if len(inTree.Rows) > 0{
        for i := 0; i < len(inTree.Rows); i++ {
            row := inTree.Rows[i]
            if row.Visible {
                if firstPoint.Y >= cTop && firstPoint.Y <= cTop + inTree.RowHeight {
                    node := row.Cells[0]
                    tLeft := cLeft + 2 + GetTotalIndent(node)
                    wLeft := tLeft
                    if inTree.ShowCheckBox {
                        wLeft += inTree.CheckBoxWidth
                        if firstPoint.X < wLeft {
                            CheckOrUnCheckTreeNode(node, !node.Checked)
                            InvalidateView(tree)
                            break
                        }
                    }
                    if len(node.ChildNodes) > 0 {
                        wLeft += inTree.CollapsedWidth
                        if firstPoint.X < wLeft {
                            node.Collapsed = !node.Collapsed
                            HideOrShowTreeNode(node, !node.Collapsed)
                            InvalidateView(tree)
                            break
                        }
                    }
                    if tree.GetPaint().OnClickTreeNode != nil{
					    tree.GetPaint().OnClickTreeNode(tree, node, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
                    }
                }
                cTop += inTree.RowHeight
            }
        }
    }
}

/*
* 表格的鼠标抬起方法
* tree: 树
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func TouchUpTree(tree *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int) {
    inTree := tree.GetTree()
    tree.HoverScrollHButton = false
    tree.HoverScrollVButton = false
    tree.DownScrollHButton = false
    tree.DownScrollVButton = false
}

/*
* 更新行的索引
* tree:树
*/
func UpdateTreeRowIndex(tree *FCView) {
    inTree := tree.GetTree()
    if len(inTree.Rows) > 0{
        for i := 0; i < len(inTree.Rows); i++ {
            inTree.Rows[i].Index = i
        }
    }
}

/*
* 获取最后一行的索引
* node:树节点
*/
func GetTreeLastNodeRowIndex(node *FCTreeNode)(int) {
    nodeRow := node.GetRow()
    rowIndex := nodeRow.Index
    if len(node.ChildNodes) > 0{
        for i := 0; i < len(node.ChildNodes); i++ {
            rIndex := GetTreeLastNodeRowIndex(node.ChildNodes[i])
            if rowIndex < rIndex {
                rowIndex = rIndex
            }
        }
    }
    return rowIndex
}

/*
* 添加节点
* tree:树
* node:要添加的节点
* parentNode:父节点
*/
func AppendTreeNode(tree *FCView, node *FCTreeNode, parentNode *FCTreeNode) {
    inTree := tree.GetTree()
    if !parentNode.IsNotEmpty {
        newRow := CreateTreeRow()
        inTree.Rows = append(inTree.Rows, newRow)
        node.SetRow(newRow)
        newRow.Cells = append(newRow.Cells, node)
        inTree.ChildNodes = append(inTree.ChildNodes, node)
    } else {
        newRow := CreateTreeRow()
        if len(parentNode.ChildNodes) == 0 {
            index := parentNode.GetRow().Index + 1
            newRows := inTree.Rows[:index]
            newRows = append(newRows, newRow)
            newRows = append(newRows, inTree.Rows[index:]...)
            inTree.Rows = newRows
        } else {
            index := GetTreeLastNodeRowIndex(parentNode) + 1
            newRows := inTree.Rows[:index]
            newRows = append(newRows, newRow)
            newRows = append(newRows, inTree.Rows[index:]...)
            inTree.Rows = newRows
        }
        node.SetParentNode(parentNode)
        node.Indent = inTree.Indent
        node.SetRow(newRow)
        newRow.Cells = append(newRow.Cells, node)
        parentNode.ChildNodes = append(parentNode.ChildNodes, node)
        if parentNode.Collapsed {
            newRow.Visible = false
        }
    }
    UpdateTreeRowIndex(tree)
}

/*
* 移除节点
* tree:树
* node:要添加的节点
*/
func RemoveTreeNode (tree *FCView, node *FCTreeNode) {
    inTree := tree.GetTree()
    //移除相互关系
    if !node.IsNotEmpty {
        nodesSize := len(inTree.ChildNodes)
        if nodesSize > 0{
            for i := 0; i < nodesSize; i++ {
                if inTree.ChildNodes[i] == node {
                    inTree.ChildNodes = append(inTree.ChildNodes[:i], inTree.ChildNodes[i + 1:]...)
                    break
                }
            }
        }
    } else {
        parentNode := node.GetParentNode()
        nodesSize := len(parentNode.ChildNodes)
        if nodesSize > 0{
            for i := 0; i < nodesSize; i++ {
                if parentNode.ChildNodes[i] == node {
                    parentNode.ChildNodes = append(parentNode.ChildNodes[:i], parentNode.ChildNodes[i + 1:]...)
                    break
                }
            }
        }
    }
    //移除行
    nodeRow := node.GetRow()
    inTree.Rows = append(inTree.Rows[:nodeRow.Index], inTree.Rows[nodeRow.Index + 1:]...)
    UpdateTreeRowIndex(tree)
}

/*
* 展开或折叠节点
* node:节点
* visible:是否可见
*/
func HideOrShowTreeNode(node *FCTreeNode, visible bool) {
    if len(node.ChildNodes) > 0 {
        for i := 0; i < len(node.ChildNodes); i++ {
            row := node.ChildNodes[i].GetRow()
            row.Visible = visible
            HideOrShowTreeNode(node.ChildNodes[i], visible)
        }
    }
}

/*
* 展开或折叠节点
* node:节点
* checked:是否选中
*/
func CheckOrUnCheckTreeNode(node *FCTreeNode, checked bool) {
    node.Checked = checked
    if len(node.ChildNodes) > 0{
        for i := 0; i < len(node.ChildNodes); i++ {
            CheckOrUnCheckTreeNode(node.ChildNodes[i], checked)
        }
    }
}

/*
* 树的鼠标滚轮方法
* tree:树
* delta:滚轮值
*/
func TouchWheelTree(tree *FCView, delta int) {
    inTree := tree.GetTree()
    oldScrollV := tree.ScrollV
    if delta > 0 {
        oldScrollV -= inTree.RowHeight
    } else if delta < 0 {
        oldScrollV += inTree.RowHeight
    }
    contentHeight := GetTreeContentHeight(tree)
    if contentHeight < tree.Size.Cy {
        tree.ScrollV = 0
    } else {
        if oldScrollV < 0 {
            oldScrollV = 0
        } else if oldScrollV > contentHeight - tree.Size.Cy + inTree.HeaderHeight + tree.ScrollSize {
            oldScrollV = contentHeight - tree.Size.Cy + inTree.HeaderHeight + tree.ScrollSize
        }
        tree.ScrollV = oldScrollV
    }
}

/*
 * 自动适应位置和大小
 * menu:菜单
 */
func AdjustMenu(menu *FCView) {
    ResetLayoutDiv(menu)
    inMenu := menu.GetMenu()
    if inMenu.AutoSize {
        contentHeight := GetDivContentHeight(menu)
        maximumHeight := menu.MaximumSize.Cy
        menu.Size.Cy = math.Min(contentHeight, maximumHeight)
    }
    mPoint := CreatePoint(menu.Location.X, menu.Location.Y)
    mSize := menu.Size
    paint := menu.GetPaint()
    nSize := CreateSize(paint.Size.Cx / paint.ScaleFactorX, paint.Size.Cy / paint.ScaleFactorY)
    if mPoint.X < 0 {
        mPoint.X = 0
    }
    if mPoint.Y < 0 {
        mPoint.Y = 0
    }
    if mPoint.X + mSize.Cx > nSize.Cx {
        mPoint.X = nSize.Cx - mSize.Cx
    }
    if mPoint.Y + mSize.Cy > nSize.Cy {
        mPoint.Y = nSize.Cy - mSize.Cy
    }
    menu.Location = mPoint
    menu.ScrollV = 0
}

/*
 * 添加菜单项
 * item:菜单项
 * menu:菜单
 */
func AddMenuItem(item *FCView, menu *FCView) {
    AddViewToParent(item, menu)
    inMenu := menu.GetMenu()
    item.GetMenuItem().SetParentMenu(menu)
    inMenu.Items = append(inMenu.Items, item)
}

/*
 * 添加菜单项
 * item:菜单项
 * parentItem:父菜单项
 */
func AddMenuItemToParent(item *FCView, parentItem *FCView) {
    inParentItem := parentItem.GetMenuItem()
    intItem := item.GetMenuItem()
    intItem.SetParentItem(parentItem)
    if !inParentItem.GetDropDownMenu().IsNotEmpty {
        newMenu := CreateView("menu")
        inParentItem.SetDropDownMenu(newMenu)
        AddView(inParentItem.GetDropDownMenu(), parentItem.GetPaint())
    }
    intItem.SetParentMenu(inParentItem.GetDropDownMenu())
    AddViewToParent(item, inParentItem.GetDropDownMenu())
    inParentItem.Items = append(inParentItem.Items, item)
    inParentItem.GetDropDownMenu().GetMenu().Items = append(inParentItem.GetDropDownMenu().GetMenu().Items, item)
}

/*
 * 控制菜单的显示隐藏
 * paint:绘图对象
 */
func CheckShowMenu(paint *FCPaint) {
    paintAll := false
    clickItem := false
    if len(paint.Views) > 0{
        for i := 0; i < len(paint.Views); i++ {
            view := paint.Views[i]
            if view.ViewType == "menu" {
                if view.Visible {
                    if view == paint.GetTouchDownView() {
                        clickItem = true
                    }
                    if len(view.GetMenu().Items) > 0{
                        for j := 0; j < len(view.GetMenu().Items); j++ {
                            item := view.GetMenu().Items[j]
                            if item == paint.GetTouchDownView() {
                                clickItem = true
                                break
                            }
                        }
                    }
                }
            }
        }
        if (!clickItem) {
            for i := 0; i < len(paint.Views); i++ {
                view := paint.Views[i]
                if view.ViewType == "menu" {
                    view.Visible = false
                    paintAll = true
                }
            }
        }
    }
    if paintAll {
        Invalidate(paint)
    }
}

/*
 * 关闭网格视图
 * items:菜单集合
 */
func CloseMenus(items []*FCView)(bool) {
    itemSize := len(items)
    close := false
    if itemSize > 0{
        for i := 0; i < itemSize; i++{
            item := items[i]
            subItems := item.GetMenuItem().Items
            if CloseMenus(subItems) {
                close = true
            }
            dropDownMenu := item.GetMenuItem().GetDropDownMenu()
            if (dropDownMenu.IsNotEmpty && dropDownMenu.Visible) {
                dropDownMenu.Visible = false
                close = true
            }
        }
    }
    return close
}

/*
 * 鼠标移动到菜单项
 * item 菜单项
 */
func TouchMoveMenuItem(item *FCView) {
    parentItem := item.GetMenuItem().GetParentItem()
    var items []*FCView
    if (parentItem.IsNotEmpty) {
        if (parentItem.GetMenuItem().GetDropDownMenu().IsNotEmpty) {
            items = parentItem.GetMenuItem().GetDropDownMenu().GetMenu().Items
        }
    } else {
        if (item.GetMenuItem().GetParentMenu().IsNotEmpty) {
            items = item.GetMenuItem().GetParentMenu().GetMenu().Items
        }
    }
    CloseMenus(items)
    if (len(item.GetMenuItem().Items) > 0) {
        dropDownMenu := item.GetMenuItem().GetDropDownMenu()
        //获取位置和大小
        if (dropDownMenu.IsNotEmpty && !dropDownMenu.Visible) {
            layoutStyle := dropDownMenu.GetLayoutDiv().LayoutStyle
            location := CreatePoint(ClientX(item) + item.Size.Cx, ClientY(item))
            if (layoutStyle == "lefttoright" || layoutStyle == "righttoleft") {
                location.X = ClientX(item)
                location.Y = ClientY(item) + item.Size.Cy
            }
            //设置弹出位置
            dropDownMenu.Location = location
            dropDownMenu.Visible = true
            AdjustMenu(dropDownMenu)
            Invalidate(item.GetPaint())
            return
        }
    }
    Invalidate(item.GetPaint())
}

/*
* 重绘按钮
* item:菜单项
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawMenuItem(item *FCView, paint *FCPaint, clipRect FCRect) {
    if (item == paint.GetTouchDownView()) {
        if (item.PushedColor != "none") {
            paint.FillRect(item.PushedColor, 0, 0, item.Size.Cx, item.Size.Cy)
        } else {
            if (item.BackColor != "none") {
                paint.FillRect(item.BackColor, 0, 0, item.Size.Cx, item.Size.Cy)
            }
        }
    } else if (item == paint.GetTouchMoveView()) {
        if (item.HoveredColor != "none") {
            paint.FillRect(item.HoveredColor, 0, 0, item.Size.Cx, item.Size.Cy)
        } else {
            if (item.BackColor != "none") {
                paint.FillRect(item.BackColor, 0, 0, item.Size.Cx,  item.Size.Cy)
            }
        }
    } else if (item.BackColor != "none") {
        paint.FillRect(item.BackColor, 0, 0, item.Size.Cx, item.Size.Cy)
    }
    if (item.TextColor != "none" && len(item.Text) > 0) {
        tSize := paint.TextSize(item.Text, item.Font)
        paint.DrawText(item.Text, item.TextColor, item.Font, (item.Size.Cx - tSize.Cx) / 2, (item.Size.Cy - tSize.Cy) / 2)
    }
    if (item.BorderColor != "none") {
        paint.DrawRect(item.BorderColor, item.BorderWidth, 0, 0, 0, item.Size.Cx, item.Size.Cy)
    }
    if (len(item.GetMenuItem().Items) > 0){
		tR := 5.0
        var drawPoints []FCPoint
        drawPoints = append(drawPoints, CreatePoint(item.Size.Cx - 2, item.Size.Cy / 2))
        drawPoints = append(drawPoints, CreatePoint(item.Size.Cx - 2 - tR * 2, item.Size.Cy / 2 - tR))
        drawPoints = append(drawPoints, CreatePoint(item.Size.Cx - 2 - tR * 2, item.Size.Cy / 2 + tR))
        paint.FillPolygon(item.TextColor, drawPoints)
    }
}

/*
 * 点击菜单项
 * item:菜单项
 */
func ClickMenuItem(item *FCView) {
    paintAll := false
    inItem := item.GetMenuItem()
    if inItem.GetParentMenu().IsNotEmpty {
        if inItem.GetParentMenu().GetMenu().GetComboBox().IsNotEmpty {
            index := -1
            if len(inItem.GetParentMenu().GetMenu().Items) > 0{
                for i := 0; i < len(inItem.GetParentMenu().GetMenu().Items); i++{
                    if inItem.GetParentMenu().GetMenu().Items[i] == item {
                        index = i
                        break
                    }
                }
                inItem.GetParentMenu().GetMenu().GetComboBox().GetComboBox().SelectedIndex = index
                inItem.GetParentMenu().GetMenu().GetComboBox().Text = inItem.GetParentMenu().GetMenu().Items[index].Text
                paintAll = true
            }
        }
    }
    if len(inItem.Items) == 0 {
        for i := 0; i < len(item.GetPaint().Views); i++{
            subView := item.GetPaint().Views[i]
            if subView.ViewType == "menu" {
                if subView.Visible {
                    subView.Visible = false
                    paintAll = true
                }
            }
        }
    }
    if paintAll {
        Invalidate(item.GetPaint())
    }
}

/*
* 重绘按钮
* comboBox:下拉列表
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawComboBox(comboBox *FCView, paint *FCPaint, clipRect FCRect) {
    if comboBox.BackColor != "none" {
        paint.FillRect(comboBox.BackColor, 0, 0, comboBox.Size.Cx, comboBox.Size.Cy)
    }
    if comboBox.TextColor != "none" && len(comboBox.Text) > 0 {
        tSize := paint.TextSize(comboBox.Text, comboBox.Font)
        paint.DrawText(comboBox.Text, comboBox.TextColor, comboBox.Font, 5, (comboBox.Size.Cy - tSize.Cy) / 2)
    }
    if comboBox.BorderColor != "none" {
        paint.DrawRect(comboBox.BorderColor, comboBox.BorderWidth, 0, 0, 0, comboBox.Size.Cx, comboBox.Size.Cy)
    }
    tR := 5.0
    var drawPoints []FCPoint
    drawPoints = append(drawPoints, CreatePoint(comboBox.Size.Cx - 5 - tR * 2, comboBox.Size.Cy / 2 - tR))
    drawPoints = append(drawPoints, CreatePoint(comboBox.Size.Cx - 5, comboBox.Size.Cy / 2 - tR))
    drawPoints = append(drawPoints, CreatePoint(comboBox.Size.Cx - 5 - tR, comboBox.Size.Cy / 2 + tR))
    paint.FillPolygon(comboBox.TextColor, drawPoints)
}

/*
 * 点击下拉菜单
 * comboBox:下拉菜单
 */
func ClickComboBox(comboBox *FCView) {
    showX := ClientX(comboBox)
    showY := ClientY(comboBox) + comboBox.Size.Cy
    inComboBox := comboBox.GetComboBox()
    inComboBox.GetDropDownMenu().Location = CreatePoint(showX, showY)
    inComboBox.GetDropDownMenu().Visible = true
    AdjustMenu(inComboBox.GetDropDownMenu())
    Invalidate(comboBox.GetPaint())
}

/*
* 计算直线参数
* mp:坐标
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
* oX:坐标起始X
* oY:坐标起始Y
*/
func LineXY(chart *FCView, x1 float64, y1 float64, x2 float64, y2 float64, oX float64, oY float64) {
    inChart := chart.GetChart()
    inChart.KChart = 0
    inChart.BChart = 0
    if (x1 - oX) != (x2 - oX) {
        inChart.KChart = ((y2 - oY) - (y1 - oY)) / ((x2 - oX) - (x1 - oX))
        inChart.BChart = (y1 - oY) - inChart.KChart * (x1 - oX)
    }
}

/*
* 判断是否选中直线
* mp:坐标
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
*/
func SelectLine(chart *FCView, mp FCPoint, x1 float64, y1 float64, x2 float64, y2 float64)(bool){
    inChart := chart.GetChart()
    LineXY(chart, x1, y1, x2, y2, 0, 0)
	if !(inChart.KChart == 0 && inChart.BChart == 0) {
        if mp.Y / (mp.X * inChart.KChart + inChart.BChart) >= 0.9 && mp.Y / (mp.X * inChart.KChart + inChart.BChart) <= 1.1 {
            return true
        }
    } else {
        if mp.X >= x1 - inChart.PlotPointSizeChart && mp.X <= x1 + inChart.PlotPointSizeChart {
            return true
        }
    }
    return false
}

/*
* 判断是否选中射线
* mp:坐标
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
*/
func SelectRay(chart *FCView, mp FCPoint, x1 float64, y1 float64, x2 float64, y2 float64)(bool){
    LineXY(chart, x1, y1, x2, y2, 0, 0)
    inChart := chart.GetChart()
    if !(inChart.KChart == 0 && inChart.BChart == 0) {
        if mp.Y / (mp.X * inChart.KChart + inChart.BChart) >= 0.9 && mp.Y / (mp.X * inChart.KChart + inChart.BChart) <= 1.1 {
            if x1 >= x2 {
                if mp.X > x1 + inChart.PlotPointSizeChart {
                    return false
                }
            } else if x1 < x2 {
                if mp.X < x1 - inChart.PlotPointSizeChart{
                    return false
                }
            }
            return true
        }
    } else {
        if mp.X >= x1 - inChart.PlotPointSizeChart && mp.X <= x1 + inChart.PlotPointSizeChart {
            if y1 >= y2 {
                if mp.Y <= y1 - inChart.PlotPointSizeChart {
                    return true
                }
            } else {
                if mp.Y >= y1 - inChart.PlotPointSizeChart {
                    return true
                }
            }
        }
    }
    return false
}

/*
* 判断是否选中线段
* mp:坐标
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
*/
func SelectSegment(chart *FCView, mp FCPoint, x1 float64, y1 float64, x2 float64, y2 float64)(bool){
    LineXY(chart, x1, y1, x2, y2, 0, 0)
    smallX := 0.0
    smallY := 0.0
    bigX := 0.0
    bigY := 0.0
    if x1 <= x2{
        smallX = x1
    }else{
        smallX = x2
    }
    if y1 <= y2{
        smallY = y1
    }else{
        smallY = y2
    }
    if x1 > x2{
        bigX = x1
    }else{
        bigX = x2
    }
    if y1 > y2{
        bigY = y1
    }else{
        bigY = y2
    }
    inChart := chart.GetChart()
    if mp.X >= smallX - 2 && mp.X <= bigX + 2 && mp.Y >= smallY - 2 && mp.Y <= bigY + 2 {
        if (inChart.KChart != 0 || inChart.BChart != 0) {
            if mp.Y / (mp.X * inChart.KChart + inChart.BChart) >= 0.9 && mp.Y / (mp.X * inChart.KChart + inChart.BChart) <= 1.1 {
                return true
            }
        } else {
            if mp.X >= x1 - inChart.PlotPointSizeChart && mp.X <= x1 + inChart.PlotPointSizeChart {
                return true
            }
        }
    }
    return false
}

/*
* 根据三点计算圆心
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
* x3:横坐标3
* y3:纵坐标3
*/
func EllipseOR(chart *FCView, x1 float64, y1 float64, x2 float64, y2 float64, x3 float64, y3 float64) {
    inChart := chart.GetChart()
    inChart.OXChart = ((y3 - y1) * (y2 * y2 - y1 * y1 + x2 * x2 - x1 * x1) + (y2 - y1) * (y1 * y1 - y3 * y3 + x1 * x1 - x3 * x3)) / (2.0 * (x2 - x1) * (y3 - y1) - 2.0 * (x3 - x1) * (y2 - y1))
    inChart.OYChart = ((x3 - x1) * (x2 * x2 - x1 * x1 + y2 * y2 - y1 * y1) + (x2 - x1) * (x1 * x1 - x3 * x3 + y1 * y1 - y3 * y3)) / (2.0 * (y2 - y1) * (x3 - x1) - 2.0 * (y3 - y1) * (x2 - x1))
	inChart.RChart = math.Sqrt(float64((x1 - inChart.OXChart) * (x1 - inChart.OXChart) + (y1 - inChart.OYChart) * (y1 - inChart.OYChart)))
}

/*
* 判断点是否在椭圆上
* x:横坐标
* y:纵坐标
* oX:坐标起始X
* oY:坐标起始Y
* a:椭圆参数a
* b:椭圆参数b
*/
func EllipseHasPoint(ix float64, iy float64, oX float64, oY float64,  a float64, b float64)(bool){
    newX := ix
	newY := iy
	newX = ix - oX
    newY = iy - oY
    if a == 0.0 && b == 0.0 && newX == 0.0 && newY == 0.0 {
        return true
    }
    if a == 0.0 {
        if newX == 0.0 && newY >= -b && newY <= b {
            return false
        }
    }
    if b == 0.0 {
        if iy == 0.0 && newX >= -a && newX <= a {
            return true
        }
    }
    if (newX * newX) / (a * a) + (newY * newY) / (b * b) >= 0.8 && (newX * newX) / (a * a) + (newY * newY) / (b * b) <= 1.2 {
        return true
    }
    return false
}

/*
* 计算线性回归
* list:集合
*/
func LinearRegressionEquation(chart *FCView, list []float64){
    sumX := 0.0
    sumY := 0.0
    sumUp := 0.0
    sumDown := 0.0
    xAvg := 0.0
    yAvg := 0.0
    inChart := chart.GetChart()
    inChart.KChart = 0
    inChart.BChart = 0
    length := len(list)
    if length > 1{
		for i := 0; i < length; i++ {
			sumX = sumX + float64(i) + 1.0
            sumY = sumY + list[i]
		}
        xAvg = sumX / float64(length)
        yAvg = sumY / float64(length)
		for i := 0; i < length; i++ {
			sumUp = sumUp + (float64(i) + 1.0 - xAvg) * (list[i] - yAvg)
            sumDown = sumDown + (float64(i) + 1.0 - xAvg) * (float64(i) + 1.0 - xAvg)
		}
        inChart.KChart = sumUp / sumDown
        inChart.BChart = yAvg - inChart.KChart * xAvg
    }
}

/*
* 计算最大值
* list:集合
*/
func MaxValue(list []float64)(float64){
    length := len(list)
	max := 0.0
	if length > 0{
		max = list[0]
	}
	for i := 0; i < length; i++ {
		if max < list[i]{
			max = list[i]
		}
	}
	return max
}

/*
* 计算最小值
* list:集合
*/
func MinValue(list []float64)(float64){
    length := len(list)
	min := 0.0
	if length > 0{
		min = list[0]
	}
	for i := 0; i < length; i++ {
		if min > list[i]{
			min = list[i]
		}
	}
	return min
}

/*
* 计算平均值
* list:集合
*/
func AvgValue(list []float64)(float64){
    length := len(list)
	sum := 0.0
	for i := 0; i < length; i++ {
		sum = sum + list[i]
	}
	sum = sum / float64(length)
	return sum
}

/*
* 计算平行四边形参数
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
* x3:横坐标3
* y3:纵坐标3
*/
func Parallelogram(chart *FCView, x1 float64, y1 float64, x2 float64, y2 float64, x3 float64, y3 float64) {
    inChart := chart.GetChart()
    inChart.X4Chart = x1 + x3 - x2
    inChart.Y4Chart = y1 + y3 - y2
}

/*
* 获取图表的区域
* chart: 图表
* plot: 画线
*/
func GetCandleRange(chart *FCView, plot *FCPlot) {
    inChart := chart.GetChart()
    bIndex := GetChartIndexByDate(chart, plot.Key1)
    eIndex := GetChartIndexByDate(chart, plot.Key2)
    tempBIndex := int(math.Min(float64(bIndex), float64(eIndex)))
    tempEIndex := int(math.Max(float64(bIndex), float64(eIndex)))
    bIndex = tempBIndex
    eIndex = tempEIndex
    var highList []float64
    var lowList []float64
    for i := bIndex; i <= eIndex; i++ {
        highList = append(highList, inChart.Data[i].High)
        lowList = append(lowList, inChart.Data[i].Low)
    }
    inChart.NHighChart = MaxValue(highList)
    inChart.NLowChart = MinValue(lowList)
}

/*
* 获取百分比线的刻度
* y1: 纵坐标1
* y2: 纵坐标2
*/
func GetPercentParams(y1 float64, y2 float64)([]float64) {
    var list []float64
    y0 := 0.0
    y25 := 0.0
    y50 := 0.0
    y75 := 0.0
    y100 := 0.0
    y0 = y1
    if y1 <= y2{
        y25 = y1 + (y2 - y1) / 4
        y50 = y1 + (y2 - y1) / 2
        y75 = y1 + (y2 - y1) * 3 / 4
    }else{
        y25 = y2 + (y1 - y2) * 3 / 4
        y50 = y2 + (y1 - y2) / 2
        y75 = y2 + (y1 - y2) / 4
    }
    y100 = y2
    list = append(list, y0)
    list = append(list, y25)
    list = append(list, y50)
    list = append(list, y75)
    list = append(list, y100)
    return list
}

/*
* 计算斐波那契数列
* index:索引
*/
func FibonacciValue(index int)(int) {
    if index < 1{
        return 0
    }
	var vList []int
	for i := 0; i < index; i++ {
		vList = append(vList, 0)
	}
	result := 0
	for i := 0; i < index; i++ {
		if i == 0 || i == 1{
			vList[i] = 1
		}else{
			vList[i] = vList[i - 1] + vList[i - 2]
		}
	}
	result = vList[index - 1]
	return result
}

/*
* 根据坐标计算矩形
* x1:横坐标1
* y1:纵坐标1
* x2:横坐标2
* y2:纵坐标2
*/
func RectangleXYWH(chart *FCView, x1 float64, y1 float64, x2 float64, y2 float64) {
    inChart := chart.GetChart()
    if x1 < x2{
		inChart.XChart = x1
	}else{
		inChart.XChart = x2
	}
	if y1 < y2{
		inChart.YChart = y1
	}else{
		inChart.YChart = y2
	}
    inChart.WChart = math.Abs(float64(x1 - x2))
    inChart.HChart = math.Abs(float64(y1 - y2))
    if inChart.WChart <= 0.0 {
        inChart.WChart = 4.0
    }
    if inChart.HChart <= 0.0 {
        inChart.HChart = 4.0
    }
}

/*
 * 计算最大值
 * @param {Object} ticks 最高价数组
 * @param {Object} days
 */
func HHVValue(ticks []float64, days int)([]float64) {
    var hhv []float64
	max := ticks[0];
	length := len(ticks)
    for i := 0; i < length; i++ {
		max = 0.0
		if i >= days{
			max = ticks[i]
            j := i
            for{
				if j > i - days{
                    if max < ticks[j] {
					    max = ticks[j]
				    }
				}else{
                    break
                }
                j = j - 1
            }
			hhv = append(hhv, max)
		} else {
			if max < ticks[i] {
				max = ticks[i]
			}
			hhv = append(hhv, max)
		}
	}
	return hhv
}

/*
 * 计算最小值
 * @param {Object} ticks 最低价数组
 * @param {Object} days
 */
func LLVValue(ticks []float64, days int)([]float64) {
    var llv []float64
	min := ticks[0];
	length := len(ticks)
    for i := 0; i < length; i++ {
		min = 0.0
		if i >= days {
			min = ticks[i]
            j := i
            for{
				if j > i - days{
                    if min > ticks[j] {
					    min = ticks[j]
				    }
				}else{
                    break
                }
                
                j = j - 1
            }
			llv = append(llv, min)
		} else {
			if min > ticks[i] {
				min = ticks[i]
			}
			llv = append(llv, min)
		}
	}
	return llv
}

/*
* REF函数
* ticks:数据
* days:日数
*/
func RefValue(ticks []float64, days int)([]float64) {
    var refArr []float64
	length := len(ticks)
    for i := 0; i < length; i++ {
		RefValue := 0.0
		if i >= days {
			RefValue = ticks[i - days]
		} else {
			RefValue = ticks[0];
		}
		refArr = append(refArr, RefValue)
	}
	return refArr
}

/*
* 获取TRIX的数据
* ticks:数据
*/
func GetTRIXData(chart *FCView, n int, m int, ticks []float64){
    inChart := chart.GetChart()
    length := len(ticks)
    var mtrArr []float64
    var emaArr1 []float64
    emaArr1 = append(emaArr1, ticks[0])
    for i := 1; i < length; i++ {
        emaArr1 = append(emaArr1, GetEMA(n, ticks[i], emaArr1[i - 1]))
    }
    var emaArr2 []float64
    emaArr2 = append(emaArr2, emaArr1[0])
    for i := 1; i < length; i++ {
        emaArr2 = append(emaArr2, GetEMA(n, emaArr1[i], emaArr2[i - 1]))
    }
    mtrArr = append(mtrArr, emaArr2[0])
    for i := 1; i < length; i++ {
        mtrArr = append(mtrArr, GetEMA(n, emaArr2[i], mtrArr[i - 1]))
    }
    ref := RefValue(mtrArr, 1)
    for i := 0; i < length; i++ {
        trix := 100.0 * (mtrArr[i] - ref[i]) / ref[i]
        inChart.Trix = append(inChart.Trix, trix)
    }
    matrixArrCopy := MaValue(inChart.Trix, m)
    for i := 0; i < len(matrixArrCopy); i++ {
        inChart.TrixMa = append(inChart.TrixMa, matrixArrCopy[i])
    }
}

/*
* 获取方差数据
*/
func StandardDeviationSum(listValue []float64, AvgValue float64)(float64){
    targetValue := listValue[len(listValue) - 1]
    sumValue := (targetValue - AvgValue) * (targetValue - AvgValue)
    for i := 0; i < len(listValue) - 1; i++ {
        ileft := listValue[i]
        sumValue = sumValue + (ileft - AvgValue) * (ileft - AvgValue)
    }
    return sumValue
}

/*
 * 计算boll指标,ma的周期为20日
 *
 * @method BOLL
 * @param {Array} ticks
 * 一维数组类型，每个元素为当前Tick的收盘价格
 * @return {Object} 返回一个包含upper mid lower属性的对象,每个属性对应的类型为{Array[Number]}
 */
func GetBollData(chart *FCView, maDays int, ticks []float64){
    inChart := chart.GetChart()
	tickBegin := maDays - 1
	maSum := 0.0
	p := 0.0
    length := len(ticks)
	for i := 0; i < length; i++ {
		c := ticks[i]
        ma := 0.0
        md := 0.0
        bstart :=  0
        mdSum := 0.0
		maSum = maSum + c;
        if i >= tickBegin {
			maSum = maSum - p;
			ma = maSum / float64(maDays)
			bstart = i - tickBegin
			p = ticks[bstart];
			inChart.BollMid = append(inChart.BollMid, ma)
			bstart = i - tickBegin
			p = ticks[bstart];
            var values []float64
            for j := bstart; j < bstart + maDays; j++ {
                values = append(values, ticks[j])
            }
            mdSum = StandardDeviationSum(values, ma)
			md = math.Sqrt(mdSum / float64(maDays))
			inChart.BollUp = append(inChart.BollUp, ma + 2.0 * md)
			inChart.BollDown = append(inChart.BollDown, ma - 2.0 * md)
		} else {
			ma = maSum / float64(i + 1)
			inChart.BollMid = append(inChart.BollMid, ma)
			var values []float64
            for j := bstart; j < bstart + maDays; j++ {
                values = append(values, ticks[j])
            }
            mdSum = StandardDeviationSum(values, ma)
			md = math.Sqrt(mdSum / float64(i + 1))
			inChart.BollUp = append(inChart.BollUp, ma + 2.0 * md)
			inChart.BollDown = append(inChart.BollDown, ma - 2.0 * md)
		}
	}
}

/*
 *
 * 计算kdj指标,rsv的周期为9日
 *
 * @method KDJ
 * @param {Array} ticks
 * 二维数组类型，其中内层数组包含三个元素值，第一个值表示当前Tick的最高价格，第二个表示当前Tick的最低价格，第三个表示当前Tick的收盘价格
 * @return {Object} 返回一个包含k d j属性的对象,每个属性对应的类型为{Array[Number]}
 */
func GetKDJData(chart *FCView, highArr []float64, lowArr []float64, closeArr []float64, n int, m1 int, m2 int) {
    inChart := chart.GetChart()
    days := n
	var rsvs []float64
    lastK := 0.0
    lastD := 0.0
    curK := 0.0
    curD :=0.0
    length := len(highArr)
	for i := 0; i < length; i++ {
		var highList []float64
		var lowList []float64
        startIndex := i - days
        if startIndex < 0{
            startIndex = 0
        }
		for j := startIndex; j <= i; j++ {
            highList = append(highList, highArr[j])
            lowList = append(highList, lowArr[j])
        }
        close := closeArr[i]
        maxHigh := 0.0
        minLow := 0.0
        for m := 0; m < len(highList); m++ {
            high := highList[m]
            low := lowList[m]
            if high > maxHigh{
                maxHigh = high
            }
            if low < minLow{
                minLow = low
            }
        }
        if maxHigh == minLow {
			rsvs = append(rsvs, 0.0)
		} else {
			rsvs = append(rsvs, (close - minLow) / (maxHigh - minLow) * 100.0)
		}
		if i == 0 {
			lastK = rsvs[i]
            lastD = rsvs[i]
		}
		curK = float64(m1 - 1.0) / float64(m1) * lastK + 1.0 / float64(m1) * rsvs[i]
		inChart.KdjK = append(inChart.KdjK, curK)
		lastK = curK

		curD = float64(m2 - 1.0) / float64(m2) * lastD + 1.0 / float64(m2) * curK
		inChart.KdjD = append(inChart.KdjD, curD)
		lastD = curD

		inChart.KdjJ = append(inChart.KdjJ, 3.0 * curK - 2.0 * curD)
    }
}

/*
 *
 * 计算rsi指标,分别返回以6日，12日，24日为参考基期的RSI值
 *
 * @method RSI
 * @param {Array} ticks
 * 一维数组类型，每个元素为当前Tick的收盘价格
 * @return {Object} 返回一个包含rsi6 rsi12 rsi24属性的对象,每个属性对应的类型为{Array[Number]}
 */
func GetRSIData(chart *FCView, n1 int, n2 int, n3 int, ticks []float64) {
    inChart := chart.GetChart()
    lastClosePx := ticks[0]
    lastSm1 :=  0.0
    lastSa1 := 0.0
    lastSm2 := 0.0
    lastSa2 := 0.0
    lastSm3 := 0.0
    lastSa3 := 0.0
    length := len(ticks)
	for i := 0; i < length; i++ {
        c := ticks[i];
		m := math.Max(c - lastClosePx, 0.0)
		a := math.Abs(c - lastClosePx)
        if i == 0{
            lastSm1 = 0.0
            lastSa1 = 0.0
            inChart.Rsi1 = append(inChart.Rsi1, 0.0)
        }else{
            lastSm1 = (m + (float64(n1 - 1)) * lastSm1) / float64(n1)
		    lastSa1 = (a + (float64(n1 - 1)) * lastSa1)/ float64(n1)
            if lastSa1 != 0.0 {
                inChart.Rsi1 = append(inChart.Rsi1, lastSm1 / lastSa1 * 100.0)
			} else {
				inChart.Rsi1 = append(inChart.Rsi1, 0.0)
			}
        }

         if i == 0{
            lastSm2 = 0.0
            lastSa2 = 0.0
            inChart.Rsi2 = append(inChart.Rsi2, 0.0)
        }else{
            lastSm2 = (m + (float64(n2 - 1)) * lastSm2) / float64(n2)
		    lastSa2 = (a + (float64(n2 - 1)) * lastSa2)/ float64(n2)
            if lastSa2 != 0.0 {
                inChart.Rsi2 = append(inChart.Rsi2, lastSm2 / lastSa2 * 100.0)
			} else {
				inChart.Rsi2 = append(inChart.Rsi2, 0.0)
			}
        }

         if i == 0{
            lastSm3 = 0.0
            lastSa3 = 0.0
            inChart.Rsi3 = append(inChart.Rsi3, 0.0)
        }else{
            lastSm3 = (m + (float64(n3 - 1)) * lastSm3) / float64(n3)
		    lastSa3 = (a + (float64(n3 - 1)) * lastSa3)/ float64(n3)
            if lastSa3 != 0.0 {
                inChart.Rsi3 = append(inChart.Rsi3, lastSm3 / lastSa3 * 100.0)
			} else {
				inChart.Rsi3 = append(inChart.Rsi3, 0.0)
			}
        }
        lastClosePx = c;
    }
}

/*
 * MA数据计算
 * @param {Object} ticks 收盘价数组
 * @param {Object} days 天数
 */
func MaValue(ticks []float64, days int)([]float64) {
    maSum := 0.0
	var mas []float64
	last := 0.0
	length := len(ticks)
	for i := 0; i < length; i++ {
		ma := 0.0
		if i >= days {
			last = ticks[i - days]
			maSum = maSum + ticks[i] - last
			ma = maSum / float64(days)
		} else {
			maSum = maSum + ticks[i]
			ma = maSum / float64(i + 1)
		}
		mas = append(mas, ma)
	}
	return mas
}

/*
 * 计算ROC数据
 * @param {Object} ticks 收盘价数组
 */
func GetRocData(chart *FCView, n int, m int, ticks []float64) {
    inChart := chart.GetChart()
	length := len(ticks)
	for i := 0; i < length; i++ {
		currRoc := 0.0
		if i >= n {
			currRoc = 100.0 * (ticks[i] - ticks[i - n]) / ticks[i - n]
			inChart.Roc = append(inChart.Roc, currRoc)
		} else {
			currRoc = 100.0 * (ticks[i] - ticks[0]) / ticks[0]
			inChart.Roc = append(inChart.Roc, currRoc)
		}
	}
	maResult := MaValue(inChart.Roc, m)
	length = len(maResult)
    for i := 0; i < length; i++ {
        inChart.RocMa = append(inChart.RocMa, maResult[i])
    }
}

/*
 * 获取BIAS的数据
 * @param {Array} ticks 收盘价数组
 * @return
 */
func GetBIASData(chart *FCView, n1 int, n2 int, n3 int, ticks []float64) {
    inChart := chart.GetChart()
    ma1 := MaValue(ticks, n1)
	ma2 := MaValue(ticks, n2)
	ma3 := MaValue(ticks, n3)
	length := len(ticks)
	for i := 0; i < length; i++ {
		b1 := (ticks[i] - ma1[i]) / ma1[i] * 100.0
		b2 := (ticks[i] - ma2[i]) / ma2[i] * 100.0
		b3 := (ticks[i] - ma3[i]) / ma3[i] * 100.0
		inChart.Bias1 = append(inChart.Bias1, b1)
		inChart.Bias2 = append(inChart.Bias2, b2)
		inChart.Bias3 = append(inChart.Bias3, b3)
	}
}

/*
 * 计算BBI(多空指标)
 * @param {Object} ticks
 */
func GetBBIData(chart *FCView, ticks []float64, n1 int, n2 int, n3 int, n4 int) {
    inChart := chart.GetChart()
    ma3 := MaValue(ticks, n1)
	ma6 := MaValue(ticks, n2)
	ma12 := MaValue(ticks, n3)
	ma24 := MaValue(ticks, n4)
	length := len(ticks)
	for i := 0; i < length; i++ {
		bbi := (ma3[i] + ma6[i] + ma12[i] + ma24[i]) / 4.0
		inChart.Bbi = append(inChart.Bbi, bbi)
	}
}

/*
 * 计算WR(威廉指标)
 * @param {Array} ticks 含最高价,最低价, 收盘价的二维数组
 * @param {Object} days
 */
func GetWRData(chart *FCView, highArr []float64, lowArr []float64, closeArr []float64, n1 int, n2 int){
    inChart := chart.GetChart()
	highArr1 := HHVValue(highArr, n1)
	highArr2 := HHVValue(highArr, n2)
	lowArr1 := LLVValue(lowArr, n1)
	lowArr2 := LLVValue(lowArr, n2)
	length := len(highArr)
	for i := 0; i < length; i++ {
		high1 := highArr1[i]
		low1 := lowArr1[i]
		high2 := highArr2[i]
		low2 := lowArr2[i]
		close := closeArr[i]
		wr1 := 100.0 * (high1 - close) / (high1 - low1)
		wr2 := 100.0 * (high2 - close) / (high2 - low2)
		inChart.Wr1 = append(inChart.Wr1, wr1)
		inChart.Wr2 = append(inChart.Wr2, wr2)
	}
}

/*
 * 计算DMA（平均差）
 * @param {Object} ticks 收盘价数组
 */
func GetDMAData(chart *FCView, n1 int, n2 int, ticks []float64) {
    inChart := chart.GetChart()
	ma10 := MaValue(ticks, n1)
	ma50 := MaValue(ticks, n2)
	length := len(ticks)
	for i := 0; i < length; i++ {
		dif := ma10[i] - ma50[i]
		inChart.Dma1 = append(inChart.Dma1, dif)
	}
    maResult := MaValue(inChart.Dma1, n1)
	length = len(maResult)
    for i := 0; i < length; i++ {
        inChart.Dma2 = append(inChart.Dma2, maResult[i])
    }
}

/*
 * CCI(顺势指标)计算  CCI（N日）=（TP－MA）÷MD÷0.015
 * @param {Object} ticks 带最高价，最低价，收盘价的二维数组
 */
func GetCCIData(chart *FCView, highArr []float64, lowArr []float64, n int, closeArr []float64) {
    inChart := chart.GetChart()
	var tpArr []float64
	length := len(closeArr)
	for i := 0; i < length; i++ {
		tpArr = append(tpArr, (highArr[i] + lowArr[i] + closeArr[i]) / 3.0)
	}
	maClose := MaValue(closeArr, n)
	var mdArr []float64
	for i := 0; i < length; i++ {
		mdArr = append(mdArr, maClose[i] - closeArr[i])
	}
	maMD := MaValue(mdArr, n)
	for i := 0; i < length; i++ {
		cci := (tpArr[i] - maClose[i]) / (maMD[i] * 0.015)
		inChart.Cci = append(inChart.Cci, cci)
	}
}

/*
* 图表的鼠标按下方法
* chart: 图表
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func TouchDownChart(chart *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint) {
    inChart := chart.GetChart()
    inChart.TouchDownPointChart = CreatePoint(firstPoint.X, firstPoint.Y)
    inChart.CrossStopIndex = GetChartIndex(chart, firstPoint)
    inChart.OffsetX = 0
	inChart.TargetOldX = 0
	inChart.TargetOldX2 = 0
    inChart.SelectShape = ""
    inChart.SelectShapeEx = ""
    var pList []*FCPlot
    inChart.SPlot = pList
    selectedPlot := SelectPlot(chart, firstPoint)
    if selectedPlot.IsNotEmpty{
        inChart.SetSelectedPlot(selectedPlot)
    }
    if !inChart.GetSelectedPlot().IsNotEmpty {
        SelectShape(chart, firstPoint)
    }
    if chart.GetPaint().IsDoubleClick{
		inChart.ShowCrossLine = !inChart.ShowCrossLine
	}
}

/*
*左滚
*chart:图表
*step:步长
*/
func ScrollLeftChart(chart *FCView, step int){
    inChart := chart.GetChart()
	inChart.OffsetX = 0
	inChart.TargetOldX = 0
	inChart.TargetOldX2 = 0
	if inChart.ShowCrossLine{
		inChart.CrossStopIndex = inChart.CrossStopIndex - step
		if inChart.CrossStopIndex >= inChart.FirstVisibleIndex{
			step = 0
		}else if inChart.CrossStopIndex < 0{
			inChart.CrossStopIndex = 0
		}
	}
	if step > 0{
		subIndex := inChart.LastVisibleIndex - inChart.FirstVisibleIndex
		fIndex := inChart.FirstVisibleIndex - step
		if fIndex < 0{
			fIndex = 0
		}
		eIndex := fIndex + subIndex
		inChart.FirstVisibleIndex = fIndex
		inChart.LastVisibleIndex = eIndex
	}
	CheckChartLastVisibleIndex(chart)
	if chart.GetPaint().OnCalculateMaxMin != nil{
        chart.GetPaint().OnCalculateMaxMin(chart)
    }else{
        CalculateChartMaxMin(chart)
    }
}

/*
*右滚
*chart:图表
*step:步长
*/
func ScrollRightChart(chart *FCView, step int){
    inChart := chart.GetChart()
	inChart.OffsetX = 0
	inChart.TargetOldX = 0
	inChart.TargetOldX2 = 0
	dataCount := len(inChart.Data)
	if inChart.ShowCrossLine{
		inChart.CrossStopIndex = inChart.CrossStopIndex + step
		if inChart.CrossStopIndex <= inChart.LastVisibleIndex{
			step = 0
		}else if inChart.CrossStopIndex > dataCount - 1{
			inChart.CrossStopIndex = dataCount - 1
		}
	}
	if step > 0{
		subIndex := inChart.LastVisibleIndex - inChart.FirstVisibleIndex
		eIndex := inChart.LastVisibleIndex + step
		if eIndex > dataCount - 1{
			eIndex = dataCount - 1
		}
		fIndex := eIndex - subIndex
		inChart.FirstVisibleIndex = fIndex
		inChart.LastVisibleIndex = eIndex
	}
	CheckChartLastVisibleIndex(chart)
	if chart.GetPaint().OnCalculateMaxMin != nil{
        chart.GetPaint().OnCalculateMaxMin(chart)
    }else{
        CalculateChartMaxMin(chart)
    }
}

/*
*图表的键盘按下事件
*chart:图表
*key:按键
*/
func keyDownChart(chart *FCView, key int){
	if (key == 38){
		ZoomOutChart(chart)
	}else if(key == 40){
		ZoomInChart(chart)
	}else if(key == 37){
		ScrollLeftChart(chart, 1)
	}else if(key == 39){
		ScrollRightChart(chart, 1)
	}
}

/*
* 添加画线
* chart: 图表
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func AddPlotDefault(chart *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint) {
    inChart := chart.GetChart()
    mp := CreatePoint(firstPoint.X, firstPoint.Y)
    if mp.Y < GetCandleDivHeight(chart) {
        touchIndex := GetChartIndex(chart, mp)
        if touchIndex >= inChart.FirstVisibleIndex && touchIndex <= inChart.LastVisibleIndex {
            if inChart.AddingPlotChart == "FiboTimezone" {
                fIndex := touchIndex
                fDate := GetChartDateByIndex(chart, fIndex)
                y := GetChartValue(chart, mp)
                newPlot := CreatePlot()
                if chart.GetPaint().DefaultUIStyle == "light" {
                    newPlot.LineColor = "rgb(0,0,0)"
                    newPlot.PointColor = "rgba(0,0,0,125)"
                } else {
                    newPlot.LineColor = "rgb(255,255,255)"
                    newPlot.PointColor = "rgba(255,255,255,125)"
                }
                newPlot.Key1 = fDate
                newPlot.Value1 = y
                newPlot.PlotType = inChart.AddingPlotChart
                inChart.Plots = append(inChart.Plots, newPlot)
                var pList []*FCPlot
                inChart.SPlot = pList
                selectedPlot := SelectPlot(chart, mp)
                if selectedPlot.IsNotEmpty{
                    inChart.SetSelectedPlot(selectedPlot)
                }
            }else if inChart.AddingPlotChart == "Triangle" || inChart.AddingPlotChart == "CircumCycle" || inChart.AddingPlotChart == "ParalleGram" || inChart.AddingPlotChart == "AngleLine" || inChart.AddingPlotChart == "Parallel" || inChart.AddingPlotChart == "SymmetricTriangle" {
                eIndex := touchIndex
                bIndex := eIndex - 5
                if bIndex >= 0 {
                    fDate := GetChartDateByIndex(chart, bIndex)
                    sDate := GetChartDateByIndex(chart, eIndex)
                    y := GetChartValue(chart, mp)
                    newPlot := CreatePlot()
                    if chart.GetPaint().DefaultUIStyle == "light" {
                        newPlot.LineColor = "rgb(0,0,0)"
                        newPlot.PointColor = "rgba(0,0,0,125)"
                    } else {
                        newPlot.LineColor = "rgb(255,255,255)"
                        newPlot.PointColor = "rgba(255,255,255,125)"
                    }
                    newPlot.Key1 = fDate
                    newPlot.Value1 = y
                    newPlot.Key2 = sDate
                    newPlot.Value2 = y
                    newPlot.Key3 = sDate
                    newPlot.Value3 = inChart.CandleMin + (inChart.CandleMax - inChart.CandleMin) / 2
                    newPlot.PlotType = inChart.AddingPlotChart
                    inChart.Plots = append(inChart.Plots, newPlot)
                    var pList []*FCPlot
                    inChart.SPlot = pList
                    selectedPlot := SelectPlot(chart, mp)
                    if selectedPlot.IsNotEmpty{
                        inChart.SetSelectedPlot(selectedPlot)
                    }
                }
            } else {
                eIndex := touchIndex
                bIndex := eIndex - 5
                if bIndex >= 0 {
                    fDate := GetChartDateByIndex(chart, bIndex)
                    sDate := GetChartDateByIndex(chart, eIndex)
                    y := GetChartValue(chart, mp)
                    newPlot := CreatePlot()
                    if chart.GetPaint().DefaultUIStyle == "light"{
                        newPlot.LineColor = "rgb(0,0,0)"
                        newPlot.PointColor = "rgba(0,0,0,125)"
                    } else {
                        newPlot.LineColor = "rgb(255,255,255)"
                        newPlot.PointColor = "rgba(255,255,255,125)"
                    }
                    newPlot.Key1 = fDate
                    newPlot.Value1 = y
                    newPlot.Key2 = sDate
                    newPlot.Value2 = y
                    newPlot.PlotType = inChart.AddingPlotChart
                    inChart.Plots = append(inChart.Plots, newPlot)
                    var pList []*FCPlot
                    inChart.SPlot = pList
                    selectedPlot := SelectPlot(chart, mp)
                    if selectedPlot.IsNotEmpty{
                        inChart.SetSelectedPlot(selectedPlot)
                    }
                }
            }
        }
    }
}

/*
* 图表的鼠标移动方法
* chart: 图表
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
*/
func TouchMoveChart(chart *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint) {
    inChart := chart.GetChart()
    if len(inChart.Data) == 0 {
        return
    }
    mp := CreatePoint(firstPoint.X, firstPoint.Y)
    inChart.CrossStopIndex = GetChartIndex(chart, mp)
    inChart.TouchPosition = mp
    inChart.OffsetX = 0
	inChart.TargetOldX = 0
	inChart.TargetOldX2 = 0
    sPlot := inChart.GetSelectedPlot()
    if firstTouch && sPlot.IsNotEmpty {
        newIndex := GetChartIndex(chart, mp)
        if newIndex >= 0 && newIndex < len(inChart.Data) {
            newDate := GetChartDateByIndex(chart, newIndex)
            newValue := GetCandleDivValue(chart, mp)
            if inChart.SelectPlotPoint == 0 {
                sPlot.Key1 = newDate
                sPlot.Value1 = newValue
            } else if inChart.SelectPlotPoint == 1 {
                sPlot.Key2 = newDate
                sPlot.Value2 = newValue
            } else if inChart.SelectPlotPoint == 2 {
                sPlot.Key3 = newDate
                sPlot.Value3 = newValue
            }else if inChart.StartMovePlot {
                bValue := GetCandleDivValue(chart, inChart.TouchDownPointChart)
                bIndex := GetChartIndex(chart, inChart.TouchDownPointChart)
                if sPlot.Key1 > 0 {
                    sPlot.Value1 = sPlot.StartValue1 + (newValue - bValue)
                    startIndex1 := GetChartIndexByDate(chart, sPlot.StartKey1)
                    newIndex1 := startIndex1 + (newIndex - bIndex)
                    if newIndex1 < 0 {
                        newIndex1 = 0
                    }else if newIndex1 > len(inChart.Data) - 1 {
                        newIndex1 = len(inChart.Data) - 1
                    }
                    sPlot.Key1 = GetChartDateByIndex(chart, newIndex1)
                }
                if sPlot.Key2 > 0 {
                    sPlot.Value2 = sPlot.StartValue2 + (newValue - bValue)
                    startIndex2 := GetChartIndexByDate(chart, sPlot.StartKey2)
                    newIndex2 := startIndex2 + (newIndex - bIndex)
                    if newIndex2 < 0 {
                        newIndex2 = 0
                    }else if (newIndex2 > len(inChart.Data) - 1) {
                        newIndex2 = len(inChart.Data) - 1
                    }
                    sPlot.Key2 = GetChartDateByIndex(chart, newIndex2)
                }
                if sPlot.Key3 > 0 {
                    sPlot.Value3 = sPlot.StartValue3 + (newValue - bValue)
                    startIndex3 := GetChartIndexByDate(chart, sPlot.StartKey3)
                    newIndex3 := startIndex3 + (newIndex - bIndex)
                    if newIndex3 < 0 {
                        newIndex3 = 0
                    }else if (newIndex3 > len(inChart.Data) - 1) {
                        newIndex3 = len(inChart.Data) - 1
                    }
                    sPlot.Key3 = GetChartDateByIndex(chart, newIndex3)
                }
            }
        }
        return
    }
    if firstTouch && secondTouch{
        if firstPoint.X > secondPoint.X {
            inChart.FirstTouchPointCacheChart = secondPoint
            inChart.SecondTouchPointCacheChart = firstPoint
        } else {
            inChart.FirstTouchPointCacheChart = firstPoint
            inChart.SecondTouchPointCacheChart = secondPoint
        }
        if inChart.FirstTouchIndexCacheChart == -1 || inChart.SecondTouchIndexCacheChart == -1 {
            inChart.FirstTouchIndexCacheChart = GetChartIndex(chart, inChart.FirstTouchPointCacheChart)
            inChart.SecondTouchIndexCacheChart = GetChartIndex(chart, inChart.SecondTouchPointCacheChart)
            inChart.FirstIndexCacheChart = inChart.FirstVisibleIndex
            inChart.LastIndexCacheChart = inChart.LastVisibleIndex
        }
    } else if firstTouch {
        inChart.SecondTouchIndexCacheChart = -1
        if inChart.FirstTouchIndexCacheChart == -1 {
            inChart.FirstTouchPointCacheChart = firstPoint
            inChart.FirstTouchIndexCacheChart = GetChartIndex(chart, inChart.FirstTouchPointCacheChart)
            inChart.FirstIndexCacheChart = inChart.FirstVisibleIndex
            inChart.LastIndexCacheChart = inChart.LastVisibleIndex
            inChart.FirstPaddingTop = inChart.CandlePaddingTop
            inChart.FirtstPaddingBottom = inChart.CandlePaddingBottom
        }
    }
    if firstTouch && secondTouch {
        if inChart.FirstTouchIndexCacheChart != -1 && inChart.SecondTouchIndexCacheChart != -1 {
            fPoint := CreatePoint(firstPoint.X, firstPoint.Y)
            sPoint := CreatePoint(secondPoint.X, secondPoint.Y)
            if firstPoint.X > secondPoint.X {
                fPoint = secondPoint
                sPoint = firstPoint
            }
            subX := math.Abs(sPoint.X - fPoint.X)
            subIndex := int(math.Abs(float64(inChart.SecondTouchIndexCacheChart - inChart.FirstTouchIndexCacheChart)))
            if subX > 0 && subIndex > 0 {
                var newScalePixel = subX / float64(subIndex)
                if newScalePixel >= 3 {
                    intScalePixel := float64(int(newScalePixel))
                    newScalePixel = intScalePixel
                }
                if newScalePixel != inChart.HScalePixel {
                    newFirstIndex := inChart.FirstTouchIndexCacheChart
                    thisX := fPoint.X
                    thisX -= newScalePixel
                    for{
                        if thisX > inChart.LeftVScaleWidth + newScalePixel{
                            newFirstIndex -= 1
                            if newFirstIndex < 0 {
                                newFirstIndex = 0
                                break
                            }
                            thisX -= newScalePixel
                        }else{
                            break
                        }
                    }
                    thisX = sPoint.X
                    newSecondIndex := inChart.SecondTouchIndexCacheChart
                    thisX += newScalePixel
                    for{
                        if thisX < chart.Size.Cx - inChart.RightVScaleWidth - newScalePixel {
                            newSecondIndex += 1
                            if newSecondIndex > len(inChart.Data) - 1 {
                                newSecondIndex = len(inChart.Data) - 1
                                break
                            }
                            thisX += newScalePixel
                        }else{
                            break
                        }                       
                    }
                    SetChartVisibleIndex(chart, newFirstIndex, newSecondIndex)
                    maxVisibleRecord := GetChartMaxVisibleCount(chart, inChart.HScalePixel, GetChartWorkAreaWidth(chart))
                    for{
                        if maxVisibleRecord < inChart.LastVisibleIndex - inChart.FirstVisibleIndex + 1 && inChart.LastVisibleIndex > inChart.FirstVisibleIndex{
                            inChart.LastVisibleIndex -= 1
                        }else{
                            break
                        }
                    }
                }
            }
        }
    } else if firstTouch {
        subIndex := int((inChart.FirstTouchPointCacheChart.X - firstPoint.X) / inChart.HScalePixel)
        if inChart.AllowDragChartDiv {
            inChart.CandlePaddingTop = inChart.FirstPaddingTop - (inChart.FirstTouchPointCacheChart.Y - firstPoint.Y)
            inChart.CandlePaddingBottom = inChart.FirtstPaddingBottom + (inChart.FirstTouchPointCacheChart.Y - firstPoint.Y)
        }
        inChart.FirstVisibleIndex = inChart.FirstIndexCacheChart + subIndex
        inChart.LastVisibleIndex = inChart.LastIndexCacheChart + subIndex
        CheckChartLastVisibleIndex(chart)
        if chart.GetPaint().OnCalculateMaxMin != nil{
            chart.GetPaint().OnCalculateMaxMin(chart)
        }else{
            CalculateChartMaxMin(chart)
        }
    }
}

/*
* 选中直线
* chart: 图表
* mp:坐标
*/
func SelectPlot(chart *FCView, mp FCPoint)(*FCPlot) {
    inChart := chart.GetChart()
    sPlot := new(FCPlot)
    sPlot.IsNotEmpty = false
    inChart.StartMovePlot = false
    inChart.SelectPlotPoint = -1
    if len(inChart.Plots) > 0{
        for i := 0; i < len(inChart.Plots); i++ {
            plot := inChart.Plots[i]
            index1 := 0
            index2 := 0
            index3 := 0
            mpx1 := 0.0
            mpy1 := 0.0
            mpx2 := 0.0
            mpy2 := 0.0
            mpx3 := 0.0
            mpy3 := 0.0
            //检查关键点
            if plot.Key1 > 0 {
                index1 = GetChartIndexByDate(chart, plot.Key1)
                mpx1 = GetChartX(chart, index1)
                mpy1 = GetChartY(chart, 0, plot.Value1)
                if mp.X >= mpx1 - inChart.PlotPointSizeChart && mp.X <= mpx1 + inChart.PlotPointSizeChart && mp.Y >= mpy1 - inChart.PlotPointSizeChart && mp.Y <= mpy1 + inChart.PlotPointSizeChart {
                    sPlot = plot
                    inChart.SelectPlotPoint = 0
                    break
                }
            }
            if plot.Key2 > 0 {
                index2 = GetChartIndexByDate(chart, plot.Key2)
                mpx2 = GetChartX(chart, index2)
                mpy2 = GetChartY(chart, 0, plot.Value2)
                if mp.X >= mpx2 - inChart.PlotPointSizeChart && mp.X <= mpx2 + inChart.PlotPointSizeChart && mp.Y >= mpy2 - inChart.PlotPointSizeChart && mp.Y <= mpy2 + inChart.PlotPointSizeChart {
                    sPlot = plot
                    inChart.SelectPlotPoint = 1
                    break
                }
            }
            if plot.Key3 > 0 {
                index3 = GetChartIndexByDate(chart, plot.Key3)
                mpx3 = GetChartX(chart, index3)
                mpy3 = GetChartY(chart, 0, plot.Value3)
                if mp.X >= mpx3 - inChart.PlotPointSizeChart && mp.X <= mpx3 + inChart.PlotPointSizeChart && mp.Y >= mpy3 - inChart.PlotPointSizeChart && mp.Y <= mpy3 + inChart.PlotPointSizeChart {
                    sPlot = plot
                    inChart.SelectPlotPoint = 2
                    break
                }
            }
            //判断其余部分的选中
            if inChart.SelectPlotPoint == -1 {
                if plot.PlotType == "Line" {
                    inChart.StartMovePlot = SelectLine(chart, mp, mpx1, mpy1, mpx2, mpy2)
                }else if plot.PlotType == "ArrowSegment" {
                    inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
                }else if plot.PlotType == "AngleLine" {
                    inChart.StartMovePlot = SelectLine(chart, mp, mpx1, mpy1, mpx2, mpy2)
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectLine(chart, mp, mpx1, mpy1, mpx3, mpy3)
                    }
                }else if plot.PlotType == "Parallel" {
                    inChart.StartMovePlot = SelectLine(chart, mp, mpx1, mpy1, mpx2, mpy2)
                    if !inChart.StartMovePlot {
                        LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                        newB := mpy3 - inChart.KChart * mpx3
                        if mpx2 == mpx1 {
                            if mp.X >= mpx3 - inChart.PlotPointSizeChart && mp.X <= mpx3 + inChart.PlotPointSizeChart {
                                inChart.StartMovePlot = true
                            }
                        } else {
                            newX1 := inChart.LeftVScaleWidth
                            newY1 := newX1 * inChart.KChart + newB
                            newX2 := chart.Size.Cx - inChart.RightVScaleWidth
                            newY2 := newX2 * inChart.KChart + newB
                            inChart.StartMovePlot = SelectLine(chart, mp, newX1, newY1, newX2, newY2)
                        }
                    }
                }else if plot.PlotType == "LRLine" {
                    inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
                }else if plot.PlotType == "Segment" {
                    inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
                } else if plot.PlotType == "Ray" {
                    inChart.StartMovePlot = SelectRay(chart, mp, mpx1, mpy1, mpx2, mpy2)
                }else if plot.PlotType == "Triangle" {
                    inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, mpx2, mpy2, mpx3, mpy3)
                    }
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx3, mpy3)
                    }
                }else if plot.PlotType == "SymmetricTriangle" {
                    if mpx2 != mpx1 {
                        a := (mpy2 - mpy1) / (mpx2 - mpx1)
                        b := mpy1 - a * mpx1
                        c := -a
                        d := mpy3 - c * mpx3
                        leftX := inChart.LeftVScaleWidth
                        leftY := leftX * a + b
                        rightX := chart.Size.Cx - inChart.RightVScaleWidth
                        rightY := rightX * a + b
                        inChart.StartMovePlot = SelectSegment(chart, mp, leftX, leftY, rightX, rightY)
                        if !inChart.StartMovePlot {
                            leftY = leftX * c + d
                            rightY = rightX * c + d
                            inChart.StartMovePlot = SelectSegment(chart, mp, leftX, leftY, rightX, rightY)
                        }
                    } else {
                        divHeight := GetCandleDivHeight(chart)
                        inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, 0, mpx1, divHeight)
                        if !inChart.StartMovePlot {
                            inChart.StartMovePlot = SelectSegment(chart, mp, mpx3, 0, mpx3, divHeight)
                        }
                    }
                }else if plot.PlotType == "Rect" {
                    sX1 := math.Min(mpx1, mpx2)
                    sY1 := math.Min(mpy1, mpy2)
                    sX2 := math.Max(mpx1, mpx2)
                    sY2 := math.Max(mpy1, mpy2)
                    inChart.StartMovePlot = SelectSegment(chart, mp, sX1, sY1, sX2, sY1)
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, sX2, sY1, sX2, sY2)
                    }
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, sX1, sY2, sX2, sY2)
                    }
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, sX1, sY1, sX1, sY2)
                    }
                }else if plot.PlotType == "BoxLine" {
                    sX1 := math.Min(mpx1, mpx2)
                    sY1 := math.Min(mpy1, mpy2)
                    sX2 := math.Max(mpx1, mpx2)
                    sY2 := math.Max(mpy1, mpy2)
                    inChart.StartMovePlot = SelectSegment(chart, mp, sX1, sY1, sX2, sY1)
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, sX2, sY1, sX2, sY2)
                    }
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, sX1, sY2, sX2, sY2)
                    }
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, sX1, sY1, sX1, sY2)
                    }
                }else if plot.PlotType == "TironeLevels" {
                    sX1 := math.Min(mpx1, mpx2)
                    sY1 := math.Min(mpy1, mpy2)
                    sX2 := math.Max(mpx1, mpx2)
                    sY2 := math.Max(mpy1, mpy2)
                    inChart.StartMovePlot = SelectSegment(chart, mp, sX1, sY1, sX2, sY1)
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, sX1, sY2, sX2, sY2)
                    }
                }else if plot.PlotType == "QuadrantLines"{
                    sX1 := math.Min(mpx1, mpx2)
                    sY1 := math.Min(mpy1, mpy2)
                    sX2 := math.Max(mpx1, mpx2)
                    sY2 := math.Max(mpy1, mpy2)
                    inChart.StartMovePlot = SelectSegment(chart, mp, sX1, sY1, sX2, sY1)
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, sX1, sY2, sX2, sY2)
                    }
                }else if plot.PlotType == "GoldenRatio" {
                    sY1 := math.Min(mpy1, mpy2)
                    sY2 := math.Max(mpy1, mpy2)
                    var ranges []float64
                    ranges = append(ranges, 0)
                    ranges = append(ranges, 0.236)
                    ranges = append(ranges, 0.382)
                    ranges = append(ranges, 0.5)
                    ranges = append(ranges, 0.618)
                    ranges = append(ranges, 0.809)
                    ranges = append(ranges, 1)
                    ranges = append(ranges, 1.382)
                    ranges = append(ranges, 1.618)
                    ranges = append(ranges, 2)
                    ranges = append(ranges, 2.382)
                    ranges = append(ranges, 2.618)
                    for j := 0; j < len(ranges); j++ {
                        newY := 0.0
                        if sY1 <= sY2{
                            newY = sY1 + (sY2 - sY1) * ranges[j]
                        }else{
                            newY = sY2 + (sY1 - sY2) * (1 - ranges[j])
                        }
                        inChart.StartMovePlot = SelectSegment(chart, mp, inChart.LeftVScaleWidth, newY, chart.Size.Cx - inChart.RightVScaleWidth, newY)
                        if inChart.StartMovePlot {
                            break
                        }
                    }
                }else if plot.PlotType == "Cycle" {
                    r := math.Sqrt(math.Abs((mpx2 - mpx1) * (mpx2 - mpx1) + (mpy2 - mpy1) * (mpy2 - mpy1)))
                    round := (mp.X - mpx1) * (mp.X - mpx1) + (mp.Y - mpy1) * (mp.Y - mpy1)
                    if round / (r * r) >= 0.9 && round / (r * r) <= 1.1 {
                        inChart.StartMovePlot = true
                    }
                } else if plot.PlotType == "CircumCycle" {
                    EllipseOR(chart, mpx1, mpy1, mpx2, mpy2, mpx3, mpy3)
                    round := (mp.X - inChart.OXChart) * (mp.X - inChart.OXChart) + (mp.Y - inChart.OYChart) * (mp.Y - inChart.OYChart)
                    if round / (inChart.RChart * inChart.RChart) >= 0.9 && round / (inChart.RChart * inChart.RChart) <= 1.1 {
                        inChart.StartMovePlot = true
                    }
                }else if plot.PlotType == "Ellipse" {
                    x1 := 0.0
                    y1 := 0.0
                    x2 := 0.0
                    y2 := 0.0
                    if mpx1 <= mpx2 {
                        x1 = mpx2
                        y1 = mpy2
                        x2 = mpx1
                        y2 = mpy1
                    } else {
                        x1 = mpx1
                        y1 = mpy1
                        x2 = mpx2
                        y2 = mpy2
                    }
                    x := x1 - (x1 - x2)
                    y := 0.0
                    width := (x1 - x2) * 2
                    height := 0.0
                    if y1 >= y2 {
                        height = (y1 - y2) * 2
                    }else {
                        height = (y2 - y1) * 2
                    }
                    y = y2 - height / 2
                    a := width / 2
                    b := height / 2
                    inChart.StartMovePlot = EllipseHasPoint(mp.X, mp.Y, x + (width / 2), y + (height / 2), a, b)
                }else if plot.PlotType == "LRBand" {
                    inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
                    if !inChart.StartMovePlot {
                        var list []float64
                        minIndex := int(math.Min(float64(index1), float64(index2)))
                        maxIndex := int(math.Max(float64(index1), float64(index2)))
                        for j := minIndex; j <= maxIndex; j++ {
                            list = append(list, inChart.Data[j].Close)
                        }
                        LinearRegressionEquation(chart, list)
                        GetLRBandRange(chart, plot, inChart.KChart, inChart.BChart)
                        mpy1 = GetChartY(chart, 0, plot.Value1 + inChart.UpSubValue)
                        mpy2 = GetChartY(chart, 0, plot.Value2 + inChart.UpSubValue)
                        inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
                        if !inChart.StartMovePlot {
                            mpy1 = GetChartY(chart, 0, plot.Value1 - inChart.DownSubValue)
                            mpy2 = GetChartY(chart, 0, plot.Value2 - inChart.DownSubValue)
                            inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
                        }
                    }
                }else if (plot.PlotType == "LRChannel") {
                    LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                    rightX := chart.Size.Cx - inChart.RightVScaleWidth
                    rightY := rightX * inChart.KChart + inChart.BChart
                    inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, rightX, rightY)
                    if !inChart.StartMovePlot {
                        var list []float64
                        minIndex := int(math.Min(float64(index1), float64(index2)))
                        maxIndex := int(math.Max(float64(index1), float64(index2)))
                        for j := minIndex; j <= maxIndex; j++ {
                            list = append(list, inChart.Data[j].Close)
                        }
                        LinearRegressionEquation(chart, list)
                        GetLRBandRange(chart, plot, inChart.KChart, inChart.BChart)
                        mpy1 = GetChartY(chart, 0, plot.Value1 + inChart.UpSubValue)
                        mpy2 = GetChartY(chart, 0, plot.Value2 + inChart.UpSubValue)
                        LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                        rightY = rightX * inChart.KChart + inChart.BChart
                        inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, rightX, rightY)
                        if !inChart.StartMovePlot {
                            mpy1 = GetChartY(chart, 0, plot.Value1 - inChart.DownSubValue)
                            mpy2 = GetChartY(chart, 0, plot.Value2 - inChart.DownSubValue)
                            LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                            rightY = rightX * inChart.KChart + inChart.BChart
                            inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, rightX, rightY)
                        }
                    }
                }else if (plot.PlotType == "ParalleGram") {
                    Parallelogram(chart, mpx1, mpy1, mpx2, mpy2, mpx3, mpy3)
                    inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
                    if !inChart.StartMovePlot {
                        inChart.StartMovePlot = SelectSegment(chart, mp, mpx2, mpy2, mpx3, mpy3)
                        if !inChart.StartMovePlot {
                            inChart.StartMovePlot = SelectSegment(chart, mp, mpx3, mpy3, inChart.X4Chart, inChart.Y4Chart)
                            if !inChart.StartMovePlot {
                                inChart.StartMovePlot = SelectSegment(chart, mp, inChart.X4Chart, inChart.Y4Chart, mpx1, mpy1)
                            }
                        }
                    }
                }else if (plot.PlotType == "SpeedResist") {
                    inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
                    if !inChart.StartMovePlot {
                        if (mpx1 != mpx2 && mpy1 != mpy2) {
                            firstP := CreatePoint(mpx2, mpy2 - (mpy2 - mpy1) / 3)
                            secondP := CreatePoint(mpx2, mpy2 - (mpy2 - mpy1) * 2 / 3)
                            startP := CreatePoint(mpx1, mpy1)
                            fK := 0.0
                            fB := 0.0
                            sK := 0.0
                            sB := 0.0
                            LineXY(chart, startP.X, startP.Y, firstP.X, firstP.Y, 0, 0)
                            fK = inChart.KChart
                            fB = inChart.BChart
                            LineXY(chart, startP.X, startP.Y, secondP.X, secondP.Y, 0, 0)
                            sK = inChart.KChart
                            sB = inChart.BChart
                            newYF := 0.0
                            newYS := 0.0
                            newX := 0.0
                            if mpx2 > mpx1 {
                                newYF = fK * (chart.Size.Cx - inChart.RightVScaleWidth) + fB
                                newYS = sK * (chart.Size.Cx - inChart.RightVScaleWidth) + sB
                                newX = (chart.Size.Cx - inChart.RightVScaleWidth)
                            }else {
                                newYF = fB
                                newYS = sB
                                newX = inChart.LeftVScaleWidth
                            }
                            inChart.StartMovePlot = SelectSegment(chart, mp, startP.X, startP.Y, newX, newYF)
                            if !inChart.StartMovePlot {
                                inChart.StartMovePlot = SelectSegment(chart, mp, startP.X, startP.Y, newX, newYS)
                            }
                        }
                    }
                }else if plot.PlotType == "FiboFanline" {
                    inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, mpy1, mpx2, mpy2)
                    if !inChart.StartMovePlot {
                        if mpx1 != mpx2 && mpy1 != mpy2 {
                            firstP := CreatePoint(mpx2, mpy2 - (mpy2 - mpy1) * 0.382)
                            secondP := CreatePoint(mpx2, mpy2 - (mpy2 - mpy1) * 0.5)
                            thirdP := CreatePoint(mpx2, mpy2 - (mpy2 - mpy1) * 0.618)
                            startP := CreatePoint(mpx1, mpy1)
                            var listP []FCPoint
                            listP = append(listP, firstP)
                            listP = append(listP, secondP)
                            listP = append(listP, thirdP)
                            listSize := len(listP)
                            for j := 0; j < listSize; j++ {
                                LineXY(chart, startP.X, startP.Y, listP[j].X, listP[j].Y, 0, 0)
                                newX := 0.0
                                newY := 0.0
                                if mpx2 > mpx1 {
                                    newY = inChart.KChart * (chart.Size.Cx - inChart.RightVScaleWidth) + inChart.BChart
                                    newX = (chart.Size.Cx - inChart.RightVScaleWidth)
                                }else {
                                    newY = inChart.BChart
                                    newX = inChart.LeftVScaleWidth
                                }
                                inChart.StartMovePlot = SelectSegment(chart, mp, startP.X, startP.Y, newX, newY)
                                if inChart.StartMovePlot {
                                    break
                                }
                            }
                        }
                    }
                }else if plot.PlotType == "FiboTimezone" {
                    fValue := 1
                    aIndex := index1
                    pos := 1
                    divHeight := GetCandleDivHeight(chart)
                    inChart.StartMovePlot = SelectSegment(chart, mp, mpx1, 0, mpx1, divHeight)
                    if !inChart.StartMovePlot {
                        for{
                            if aIndex + fValue <= inChart.LastVisibleIndex{
                                fValue = FibonacciValue(pos)
                                newIndex := aIndex + fValue
                                newX := GetChartX(chart, newIndex)
                                inChart.StartMovePlot = SelectSegment(chart, mp, newX, 0, newX, divHeight)
                                if inChart.StartMovePlot {
                                    break
                                }
                                pos += 1
                            }else{
                                break
                            }
                        }
                    }
                }else if plot.PlotType == "Percent" {
                    list := GetPercentParams(mpy1, mpy2)
                    for j := 0; j < len(list); j++ {
                        inChart.StartMovePlot = SelectSegment(chart, mp, inChart.LeftVScaleWidth, list[j], chart.Size.Cx - inChart.RightVScaleWidth, list[j])
                        if inChart.StartMovePlot {
                            break
                        }
                    }
                }
                if inChart.StartMovePlot {
                    sPlot = plot
                    plot.StartKey1 = plot.Key1
                    plot.StartValue1 = plot.Value1
                    plot.StartKey2 = plot.Key2
                    plot.StartValue2 = plot.Value2
                    plot.StartKey3 = plot.Key3
                    plot.StartValue3 = plot.Value3
                    break
                }
            }
        }
    }
    return sPlot
}

/*
* 计算线性回归上下限
* chart:图表
* plot:画线
* a:直线k
* b:直线b
*/
func GetLRBandRange(chart *FCView, plot *FCPlot, a float64, b float64) {
    inChart := chart.GetChart()
    bIndex := GetChartIndexByDate(chart, plot.Key1)
    eIndex := GetChartIndexByDate(chart, plot.Key2)
    tempBIndex := int(math.Min(float64(bIndex), float64(eIndex)))
    tempEIndex := int(math.Max(float64(bIndex), float64(eIndex)))
    bIndex = tempBIndex
    eIndex = tempEIndex
    var upList []float64
    var downList []float64
    for i := bIndex; i <= eIndex; i++ {
        high := inChart.Data[i].High
        low := inChart.Data[i].Low
        midValue := float64(i - bIndex + 1) * a + b
        upList = append(upList, high - midValue)
        downList = append(downList, midValue - low)
    }
    inChart.UpSubValue = MaxValue(upList)
    inChart.DownSubValue = MaxValue(downList)
}

/*
* 根据位置计算索引
* chart:图表
* mp:坐标
*/
func GetChartIndex(chart *FCView, mp FCPoint)(int){
    inChart := chart.GetChart()
    if len(inChart.Data) == 0{
        return -1
    }
    if mp.X <= 0 {
        return 0
    }
    intX := int(mp.X - inChart.LeftVScaleWidth - inChart.HScalePixel - inChart.OffsetX)
    index := inChart.FirstVisibleIndex + int(float64(intX) / inChart.HScalePixel)
    if inChart.HScalePixel > 1{
        if intX % int(inChart.HScalePixel) != 0 {
            index += 1
        }
    }
    if index < 0 {
        index = 0
    } else if index > len(inChart.Data) - 1 {
        index = len(inChart.Data) - 1
    }
    return index
}

/*
* 获取最大显示记录条数
* chart:图表
* hScalePixel:间隔
* pureH:横向距离
*/
func GetChartMaxVisibleCount(chart *FCView, hScalePixel float64, pureH float64)(int){
    count := int((pureH - hScalePixel) / hScalePixel)
    if count < 0 {
        count = 0
    }
    return count
}

/*
* 获取图表层的高度
* chart:图表
*/
func GetCandleDivHeight(chart *FCView)(float64) {
    inChart := chart.GetChart()
    height := chart.Size.Cy - inChart.HScaleHeight
    if height > 0 {
        return height * inChart.CandleDivPercent
    } else {
        return 0
    }
}

/*
* 获取成交量层的高度
* chart:图表
*/
func GetVolDivHeight(chart *FCView)(float64) {
    inChart := chart.GetChart()
    height := chart.Size.Cy - inChart.HScaleHeight
    if height > 0 {
        return height * inChart.VolDivPercent
    } else {
        return 0
    }
}

/*
* 获取指标层的高度
* chart:图表
*/
func GetIndDivHeight(chart *FCView)(float64) {
    inChart := chart.GetChart()
    height := chart.Size.Cy - inChart.HScaleHeight
    if height > 0 {
        return height * inChart.IndDivPercent
    } else {
        return 0
    }
}

/*
* 获取指标层2的高度
* chart:图表
*/
func GetIndDivHeight2(chart *FCView)(float64) {
    inChart := chart.GetChart()
    height := chart.Size.Cy - inChart.HScaleHeight
    if height > 0 {
        return height * inChart.IndDivPercent2
    } else {
        return 0
    }
}

/*
* 获取横向工作区
* chart:图表
*/
func GetChartWorkAreaWidth(chart *FCView)(float64) {
    inChart := chart.GetChart()
    return chart.Size.Cx - inChart.LeftVScaleWidth - inChart.RightVScaleWidth - inChart.RightSpace
}

/*
* 根据索引获取横坐标
* chart:图表
* index:索引
*/
func GetChartX(chart *FCView, index int)(float64) {
    inChart := chart.GetChart()
    return inChart.LeftVScaleWidth + float64(index - inChart.FirstVisibleIndex) * inChart.HScalePixel + inChart.HScalePixel + inChart.OffsetX
}

/*
* 根据日期获取索引
* chart:图表
* date:日期
*/
func GetChartIndexByDate(chart *FCView, date float64)(int) {
    inChart := chart.GetChart()
    index := -1
    if len(inChart.Data) > 0{
        for i := 0; i < len(inChart.Data); i++ {
            if inChart.Data[i].Date == date {
                index = i
                break
            }
        }
    }
    return index
}

/*
* 根据索引获取日期
* chart:图表
* index:索引
*/
func GetChartDateByIndex(chart *FCView, index int)(float64) {
    date := 0.0
    inChart := chart.GetChart()
    if len(inChart.Data) > 0{
        if index >= 0 && index < len(inChart.Data) {
            date = inChart.Data[index].Date
        }
    }
    return date
}

/*
* 计算数值在层中的位置
* chart:图表
* divIndex:所在层
* chart:数值
*/
func GetChartY(chart *FCView, divIndex int, value float64)(float64) {
    inChart := chart.GetChart()
    if divIndex == 0 {
        if inChart.CandleMax > inChart.CandleMin {
            cValue := value
            cMax := inChart.CandleMax
            cMin := inChart.CandleMin
            if inChart.VScaleType != "standard" {
                if cValue > 0 {
                    cValue = math.Log(cValue)
                } else if cValue < 0 {
                    cValue = -math.Log(math.Abs(cValue))
                }
                if cMax > 0 {
                    cMax = math.Log(cMax)
                } else if cMax < 0 {
                    cMax = -math.Log(math.Abs(cMax))
                }
                if cMin > 0 {
                    cMin = math.Log(cMin)
                } else if cMin < 0 {
                    cMin = -math.Log(math.Abs(cMin))
                }
            }
            rate := (cValue - cMin) / (cMax - cMin)
            divHeight := GetCandleDivHeight(chart)
            return divHeight - inChart.CandlePaddingBottom - (divHeight - inChart.CandlePaddingTop - inChart.CandlePaddingBottom) * rate
        } else {
            return 0
        }
    } else if divIndex == 1 {
        if inChart.VolMax > inChart.VolMin {
            rate := (value - inChart.VolMin) / (inChart.VolMax - inChart.VolMin)
            candleHeight := GetCandleDivHeight(chart)
            volHeight := GetVolDivHeight(chart)
            return candleHeight + volHeight - inChart.VolPaddingBottom - (volHeight - inChart.VolPaddingTop - inChart.VolPaddingBottom) * rate
        } else {
            return 0
        }
    } else if divIndex == 2 {
        if inChart.IndMax > inChart.IndMin {
            rate := (value - inChart.IndMin) / (inChart.IndMax - inChart.IndMin)
            candleHeight := GetCandleDivHeight(chart)
            volHeight := GetVolDivHeight(chart)
            indHeight := GetIndDivHeight(chart)
            return candleHeight + volHeight + indHeight - inChart.IndPaddingBottom - (indHeight - inChart.IndPaddingTop - inChart.IndPaddingBottom) * rate
        } else {
            return 0
        }
    }else if divIndex == 3 {
        if inChart.IndMax2 > inChart.IndMin2 {
            rate := (value - inChart.IndMin2) / (inChart.IndMax2 - inChart.IndMin2)
            candleHeight := GetCandleDivHeight(chart)
            volHeight := GetVolDivHeight(chart)
            indHeight := GetIndDivHeight(chart)
            indHeight2 := GetIndDivHeight2(chart)
            return candleHeight + volHeight + indHeight + indHeight2 - inChart.IndPaddingBottom2 - (indHeight2 - inChart.IndPaddingTop2 - inChart.IndPaddingBottom2) * rate
        } else {
            return 0
        }
    }
    return 0
}

/*
* 计算数值在层中的右轴位置
* chart:图表
* divIndex:所在层
* chart:数值
*/
func GetChartYInRight(chart *FCView, divIndex int, value float64)(float64) {
    inChart := chart.GetChart()
    if divIndex == 0 {
        if inChart.CandleMaxRight > inChart.CandleMinRight {
            cValue := value
            cMax := inChart.CandleMaxRight
            cMin := inChart.CandleMinRight
            if inChart.VScaleType != "standard" {
                if cValue > 0 {
                    cValue = math.Log(cValue)
                } else if cValue < 0 {
                    cValue = -math.Log(math.Abs(cValue))
                }
                if cMax > 0 {
                    cMax = math.Log(cMax)
                } else if cMax < 0 {
                    cMax = -math.Log(math.Abs(cMax))
                }
                if cMin > 0 {
                    cMin = math.Log(cMin)
                } else if cMin < 0 {
                    cMin = -math.Log(math.Abs(cMin))
                }
            }
            rate := (cValue - cMin) / (cMax - cMin)
            divHeight := GetCandleDivHeight(chart)
            return divHeight - inChart.CandlePaddingBottom - (divHeight - inChart.CandlePaddingTop - inChart.CandlePaddingBottom) * rate
        } else {
            return 0
        }
    } else if divIndex == 1 {
        if inChart.VolMaxRight > inChart.VolMinRight {
            rate := (value - inChart.VolMinRight) / (inChart.VolMaxRight - inChart.VolMinRight)
            candleHeight := GetCandleDivHeight(chart)
            volHeight := GetVolDivHeight(chart)
            return candleHeight + volHeight - inChart.VolPaddingBottom - (volHeight - inChart.VolPaddingTop - inChart.VolPaddingBottom) * rate
        } else {
            return 0
        }
    } else if divIndex == 2{
        if inChart.IndMaxRight > inChart.IndMinRight {
            rate := (value - inChart.IndMinRight) / (inChart.IndMaxRight - inChart.IndMinRight)
            candleHeight := GetCandleDivHeight(chart)
            volHeight := GetVolDivHeight(chart)
            indHeight := GetIndDivHeight(chart)
            return candleHeight + volHeight + indHeight - inChart.IndPaddingBottom - (indHeight - inChart.IndPaddingTop - inChart.IndPaddingBottom) * rate
        } else {
            return 0
        }
    }else if divIndex == 3 {
        if inChart.IndMax2Right > inChart.IndMin2Right {
            rate := (value - inChart.IndMin2Right) / (inChart.IndMax2Right - inChart.IndMin2Right)
            candleHeight := GetCandleDivHeight(chart)
            volHeight := GetVolDivHeight(chart)
            indHeight := GetIndDivHeight(chart)
            indHeight2 := GetIndDivHeight2(chart)
            return candleHeight + volHeight + indHeight + indHeight2 - inChart.IndPaddingBottom2 - (indHeight2 - inChart.IndPaddingTop2 - inChart.IndPaddingBottom2) * rate
        } else {
            return 0
        }
    }
    return 0
}

/*
* 根据坐标获取对应的值
* chart:图表
* point:坐标
*/
func GetChartValue(chart *FCView, point FCPoint)(float64) {
    inChart := chart.GetChart()
    candleHeight := GetCandleDivHeight(chart)
    volHeight := GetVolDivHeight(chart)
    indHeight := GetIndDivHeight(chart)
    indHeight2 := GetIndDivHeight(chart)
    if point.Y <= candleHeight {
        rate := (candleHeight - inChart.CandlePaddingBottom - point.Y) / (candleHeight - inChart.CandlePaddingTop - inChart.CandlePaddingBottom)
        cMin := inChart.CandleMin
        cMax := inChart.CandleMax
        if inChart.VScaleType != "standard" {
            if cMax > 0 {
                cMax = math.Log(cMax)
            } else if cMax < 0 {
                cMax = -math.Log(math.Abs(cMax))
            }
            if cMin > 0 {
                cMin = math.Log(cMin)
            } else if cMin < 0 {
                cMin = -math.Log(math.Abs(cMin))
            }
        }
        result := cMin + (cMax - cMin) * rate
        if inChart.VScaleType != "standard" {
            return math.Pow(10, result)
        } else {
            return result
        }
    }else if point.Y > candleHeight && point.Y <= candleHeight + volHeight {
        rate := (volHeight - inChart.VolPaddingBottom - (point.Y - candleHeight)) / (volHeight - inChart.VolPaddingTop - inChart.VolPaddingBottom)
        return inChart.VolMin + (inChart.VolMax - inChart.VolMin) * rate
    } else if point.Y > candleHeight + volHeight && point.Y <= candleHeight + volHeight + indHeight {
        rate := (indHeight - inChart.IndPaddingBottom - (point.Y - candleHeight - volHeight)) / (indHeight - inChart.IndPaddingTop - inChart.IndPaddingBottom)
        return inChart.IndMin + (inChart.IndMax - inChart.IndMin) * rate
    } else if point.Y > candleHeight + volHeight + indHeight && point.Y <= candleHeight + volHeight + indHeight + indHeight2 {
        rate := (indHeight2 - inChart.IndPaddingBottom2 - (point.Y - candleHeight - volHeight - indHeight)) / (indHeight2 - inChart.IndPaddingTop2 - inChart.IndPaddingBottom2)
        return inChart.IndMin2 + (inChart.IndMax2 - inChart.IndMin2) * rate
    }
    return 0
}

/*
* 根据坐标获取对应的值
* chart:图表
* point:坐标
*/
func GetCandleDivValue(chart *FCView, point FCPoint)(float64) {
    inChart := chart.GetChart()
    candleHeight := GetCandleDivHeight(chart)
    rate := (candleHeight - inChart.CandlePaddingBottom - point.Y) / (candleHeight - inChart.CandlePaddingTop - inChart.CandlePaddingBottom)
    cMin := inChart.CandleMin
    cMax := inChart.CandleMax
    if inChart.VScaleType != "standard" {
        if cMax > 0 {
            cMax = math.Log(cMax)
        } else if cMax < 0 {
            cMax = -math.Log(math.Abs(cMax))
        }
        if cMin > 0 {
            cMin = math.Log(cMin)
        } else if cMin < 0 {
            cMin = -math.Log(math.Abs(cMin))
        }
    }
    result := cMin + (cMax - cMin) * rate
    if inChart.VScaleType != "standard" {
        return math.Pow(10, result)
    } else {
        return result
    }
}

/*
* 检查最后可见索引
* chart:图表
*/
func CheckChartLastVisibleIndex(chart *FCView) {
    inChart := chart.GetChart()
    dataCount := len(inChart.Data)
    workingAreaWidth := GetChartWorkAreaWidth(chart)
    maxVisibleRecord := GetChartMaxVisibleCount(chart, inChart.HScalePixel, workingAreaWidth)
    if inChart.FirstVisibleIndex < 0{
        inChart.FirstVisibleIndex = 0
    }
    if (inChart.LastVisibleIndex >= inChart.FirstVisibleIndex + maxVisibleRecord - 1) || (inChart.LastVisibleIndex < dataCount - 1){
        inChart.LastVisibleIndex = inChart.FirstVisibleIndex + maxVisibleRecord - 1
    }
    if inChart.LastVisibleIndex > dataCount - 1{
        inChart.LastVisibleIndex = dataCount - 1
    }
    if len(inChart.Data) > 0 {
        inChart.LastVisibleKey = inChart.Data[inChart.LastVisibleIndex].Date
        if inChart.LastVisibleIndex == len(inChart.Data) - 1 {
            inChart.LastRecordIsVisible = true
        } else {
            inChart.LastRecordIsVisible = false
        }
    } else {
        inChart.LastVisibleKey = 0
        inChart.LastRecordIsVisible = true
    }
}

/*
* 自动设置首先可见和最后可见的记录号
* chart:图表
*/
func ResetChartVisibleRecord(chart *FCView) {
    inChart := chart.GetChart()
    rowsCount := len(inChart.Data)
    workingAreaWidth := GetChartWorkAreaWidth(chart)
    if inChart.AutoFillHScale {
        if workingAreaWidth > 0 && rowsCount > 0 {
            inChart.HScalePixel = workingAreaWidth / float64(rowsCount)
            inChart.FirstVisibleIndex = 0
            inChart.LastVisibleIndex = rowsCount - 1
        }
    } else {
        maxVisibleRecord := GetChartMaxVisibleCount(chart, inChart.HScalePixel, workingAreaWidth)
        //没数据时重置
        if rowsCount == 0 {
            inChart.FirstVisibleIndex = -1
            inChart.LastVisibleIndex = -1
        } else {
            //数据不足一屏时
            if rowsCount < maxVisibleRecord {
                inChart.LastVisibleIndex = rowsCount - 1
                inChart.FirstVisibleIndex = 0
            }else {
                //显示中间的数据时
                if inChart.FirstVisibleIndex != -1 && inChart.LastVisibleIndex != -1 && !inChart.LastRecordIsVisible {
                    index := GetChartIndexByDate(chart, inChart.LastVisibleKey)
                    if index != -1 {
                        inChart.LastVisibleIndex = index
                    }
                    inChart.FirstVisibleIndex = inChart.LastVisibleIndex - maxVisibleRecord + 1
                    if inChart.FirstVisibleIndex < 0 {
                        inChart.FirstVisibleIndex = 0
                        inChart.LastVisibleIndex = inChart.FirstVisibleIndex + maxVisibleRecord
                        CheckChartLastVisibleIndex(chart)
                    }
                } else {
                    //第一条或最后一条数据被显示时
                    inChart.LastVisibleIndex = rowsCount - 1
                    inChart.FirstVisibleIndex = inChart.LastVisibleIndex - maxVisibleRecord + 1
                    if inChart.FirstVisibleIndex > inChart.LastVisibleIndex {
                        inChart.FirstVisibleIndex = inChart.LastVisibleIndex
                    }
                }
            }
        }
    }
}

/*
* 设置可见索引
* chart:图表
* FirstVisibleIndex:起始索引
* LastVisibleIndex:结束索引
*/
func SetChartVisibleIndex(chart *FCView, FirstVisibleIndex int, LastVisibleIndex int) {
    inChart := chart.GetChart()
    xScalePixel := GetChartWorkAreaWidth(chart) / float64(LastVisibleIndex - FirstVisibleIndex + 1)
    if xScalePixel < 1000000 {
        inChart.FirstVisibleIndex = FirstVisibleIndex
        inChart.LastVisibleIndex = LastVisibleIndex
        //设置最后一条记录是否可见
        if LastVisibleIndex != len(inChart.Data) - 1 {
            inChart.LastRecordIsVisible = false
        } else {
            inChart.LastRecordIsVisible = true
        }
        inChart.HScalePixel = xScalePixel
        CheckChartLastVisibleIndex(chart)
    }
}

/*
* 清除图形
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawChart(chart *FCView, paint *FCPaint, clipRect FCRect) {
    inChart := chart.GetChart()
    if chart.BackColor != "none" {
        paint.FillRect(chart.BackColor, 0, 0, chart.Size.Cx, chart.Size.Cy)
    }
    if paint.OnPaintChartScale != nil{
        paint.OnPaintChartScale(chart, paint, clipRect)
    }else{
        DrawChartScale(chart, paint, clipRect)
    }
    if paint.OnPaintChartStock != nil{
        paint.OnPaintChartStock(chart, paint, clipRect)
    }else{
        DrawChartStock(chart, paint, clipRect)
    }
    if paint.OnPaintChartPlot != nil{
        paint.OnPaintChartPlot(chart, paint, clipRect)
    }else{
        DrawChartPlot(chart, paint, clipRect)
    }
    if paint.OnPaintChartCrossLine != nil{
        paint.OnPaintChartCrossLine(chart, paint, clipRect)
    }else{
        DrawChartCrossLine(chart, paint, clipRect)
    }
    if chart.BorderColor != "none" {
        paint.DrawRect(chart.BorderColor, inChart.LineWidthChart, 0, 0, 0, chart.Size.Cx, chart.Size.Cy)
    }
}

/*
* 计算坐标轴
* min:最小值
* max:最大值
* yLen:长度
* maxSpan:最大间隔
* minSpan:最小间隔
* defCount:数量
*/
func ChartGridScale(chart *FCView, min float64, max float64, yLen int, maxSpan float64, minSpan float64, defCount int){
    inChart := chart.GetChart()
    sub := max - min
    nMinCount := int(math.Ceil(float64(yLen) / maxSpan))
    nMaxCount := int(math.Floor(float64(yLen) / minSpan))
    nCount := defCount
    logStep := sub / float64(nCount)
    start := false
    divisor := 0.0
    i := 15
    nTemp := 0
    inChart.GridStepChart = 0
    inChart.GridDigitChart = 0
    if nMinCount > nCount{
        nCount =  nMinCount
    }
    if nMaxCount < nCount{
        nCount = nMaxCount
    }
    if nCount < 1{
        nCount =  1
    }
    for{
        if i >= -6{
            divisor = math.Pow(10.0, float64(i))
            if divisor < 1 {
                inChart.GridDigitChart += 1
            }
            nTemp = int(math.Floor(logStep / divisor))
            if start {
                if nTemp < 4 {
                    if (inChart.GridDigitChart > 0) {
                        inChart.GridDigitChart -= 1
                    }
                } else if nTemp >= 4 && nTemp <= 6 {
                    nTemp = 5
                    inChart.GridStepChart += float64(nTemp) * divisor
                } else {
                    inChart.GridStepChart += 10 * divisor
                    if inChart.GridDigitChart > 0 {
                        inChart.GridDigitChart -= 1
                    }
                }
                break
            } else if nTemp > 0{
                inChart.GridStepChart = float64(nTemp) * divisor + inChart.GridStepChart
                logStep -= inChart.GridStepChart
                start = true
            }
            i -= 1
        }else{
            break
        }
    }
}

/*
* 缩小
* chart:图表
*/
func ZoomOutChart(chart *FCView) {
    inChart := chart.GetChart()
    if !inChart.AutoFillHScale {
        hScalePixel := inChart.HScalePixel
        oldX := GetChartX(chart, inChart.CrossStopIndex)
        if inChart.ShowCrossLine && inChart.TargetOldX == 0{
			inChart.TargetOldX = oldX
		}
        pureH := GetChartWorkAreaWidth(chart)
        oriMax := -1
        max := -1
        deal := 0
        dataCount := len(inChart.Data)
        findex := inChart.FirstVisibleIndex
        lindex := inChart.LastVisibleIndex
        if hScalePixel < pureH {
            oriMax = GetChartMaxVisibleCount(chart, hScalePixel, pureH)
            if dataCount < oriMax {
                deal = 1
            }
            if hScalePixel > 3 {
                hScalePixel += 1
            } else {
                if hScalePixel == 1 {
                    hScalePixel = 2
                } else {
                    hScalePixel = hScalePixel * 1.5
                    if hScalePixel > 3 {
                        hScalePixel = float64(int(hScalePixel))
                    }
                }
            }
            max = GetChartMaxVisibleCount(chart, hScalePixel, pureH)
            if dataCount >= max {
                if deal == 1 {
                    lindex = dataCount - 1
                }
                findex = lindex - max + 1
                if (findex < 0) {
                    findex = 0
                }
            }
        }
        inChart.HScalePixel = hScalePixel
        if inChart.ShowCrossLine{
			sX := inChart.TargetOldX
			findex = inChart.CrossStopIndex
            for{
                if sX < inChart.LeftVScaleWidth + inChart.HScalePixel{
                    break
                }
                findex = findex - 1
				inChart.OffsetX = sX - inChart.LeftVScaleWidth - inChart.HScalePixel
				sX = sX - inChart.HScalePixel
            }
			findex = findex + 1
		}
		inChart.FirstVisibleIndex = findex
		inChart.LastVisibleIndex = lindex
        CheckChartLastVisibleIndex(chart)
        if chart.GetPaint().OnCalculateMaxMin != nil{
            chart.GetPaint().OnCalculateMaxMin(chart)
        }else{
            CalculateChartMaxMin(chart)
        }
    }
}

/*
* 放大
* chart:图表
*/
func ZoomInChart(chart *FCView) {
    inChart := chart.GetChart()
    if !inChart.AutoFillHScale {
        hScalePixel := inChart.HScalePixel
        oldX := GetChartX(chart, inChart.CrossStopIndex)
        if inChart.ShowCrossLine && inChart.TargetOldX2 == 0{
			inChart.TargetOldX2 = oldX
		}
        pureH := GetChartWorkAreaWidth(chart)
        max := -1
        dataCount := len(inChart.Data)
        findex := inChart.FirstVisibleIndex
        lindex := inChart.LastVisibleIndex
        if hScalePixel > 3 {
            hScalePixel -= 1
        } else {
            hScalePixel = hScalePixel * 2 / 3
            if hScalePixel > 3 {
                hScalePixel = float64(int(hScalePixel))
            }
        }
        max = GetChartMaxVisibleCount(chart, hScalePixel, pureH)
        if max >= dataCount {
            if hScalePixel < 1 {
                hScalePixel = pureH / float64(max)
            }
            findex = 0
            lindex = dataCount - 1
        } else {
            findex = lindex - max + 1
            if (findex < 0) {
                findex = 0
            }
        }
        inChart.HScalePixel = hScalePixel
        if inChart.ShowCrossLine{
			sX := inChart.TargetOldX2
			findex = inChart.CrossStopIndex
            for{
                if sX < inChart.LeftVScaleWidth + inChart.HScalePixel{
                    break
                }
                findex = findex - 1
				inChart.OffsetX = sX - inChart.LeftVScaleWidth - inChart.HScalePixel
				sX = sX - inChart.HScalePixel
            }
			findex = findex + 1
		}
		inChart.FirstVisibleIndex = findex
		inChart.LastVisibleIndex = lindex
        CheckChartLastVisibleIndex(chart)
        if chart.GetPaint().OnCalculateMaxMin != nil{
            chart.GetPaint().OnCalculateMaxMin(chart)
        }else{
            CalculateChartMaxMin(chart)
        }
    }
}

/*
* 绘制刻度
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawChartScale(chart *FCView, paint *FCPaint, clipRect FCRect) {
    inChart := chart.GetChart()
    if inChart.LeftVScaleWidth > 0 {
        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth, 0, inChart.LeftVScaleWidth, chart.Size.Cy - inChart.HScaleHeight)
    }
    if inChart.RightVScaleWidth > 0 {
        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, chart.Size.Cx - inChart.RightVScaleWidth, 0, chart.Size.Cx - inChart.RightVScaleWidth, chart.Size.Cy - inChart.HScaleHeight)
    }
    if inChart.HScaleHeight > 0 {
        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, 0, chart.Size.Cy - inChart.HScaleHeight, chart.Size.Cx, chart.Size.Cy - inChart.HScaleHeight)
    }
    candleDivHeight := GetCandleDivHeight(chart)
    volDivHeight := GetVolDivHeight(chart)
    indDivHeight := GetIndDivHeight(chart)
    indDivHeight2 := GetIndDivHeight2(chart)
    if volDivHeight > 0 {
        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth, candleDivHeight, chart.Size.Cx - inChart.RightVScaleWidth, candleDivHeight)
    }
    if indDivHeight > 0 {
        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth, candleDivHeight + volDivHeight, chart.Size.Cx - inChart.RightVScaleWidth, candleDivHeight + volDivHeight)
    }
    if indDivHeight2 > 0 {
        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth, candleDivHeight + volDivHeight + indDivHeight, chart.Size.Cx - inChart.RightVScaleWidth, candleDivHeight + volDivHeight + indDivHeight)
    }
    if len(inChart.Data) == 0{
        return
    }
    topPoint := CreatePoint(0, 10)
    bottomPoint := CreatePoint(0, candleDivHeight - 10)
    candleMax := GetChartValue(chart, topPoint)
    candleMin := GetChartValue(chart, bottomPoint)
    ChartGridScale(chart, candleMin, candleMax, int((candleDivHeight - inChart.CandlePaddingTop - inChart.CandlePaddingBottom) / 2), inChart.VScaleDistance, inChart.VScaleDistance / 2, int((candleDivHeight - inChart.CandlePaddingTop - inChart.CandlePaddingBottom) / inChart.VScaleDistance))
    if inChart.GridStepChart > 0 {
        var drawValues []float64
        isTrend := false
        if inChart.Cycle == "trend"{
            isTrend = true
        }
        firstOpen := 0.0
        if isTrend {
            firstOpen = inChart.Data[inChart.FirstVisibleIndex].Close
            subValue := (candleMax - candleMin)
            count := int((candleDivHeight - inChart.CandlePaddingTop - inChart.CandlePaddingBottom) / inChart.VScaleDistance)
            if count > 0 {
                subValue /= float64(count)
            }
            start := firstOpen
            for{
                if start < candleMax {
                    start += subValue
                    if start <= candleMax {
                        drawValues = append(drawValues, start)
                    }
                }else{
                    break
                }
            }
            start = firstOpen
            for{
                if start > candleMin {
                    start -= subValue
                    if start >= candleMin {
                        drawValues = append(drawValues, start)
                    }
                }else{
                    break
                }
            }
        } else {
            start := 0.0
            if candleMin >= 0 {
                for{
                    if start + inChart.GridStepChart < candleMin {
                        start += inChart.GridStepChart
                    }else{
                        break
                    }
                }
            } else {
                for{
                    if start - inChart.GridStepChart > candleMin {
                        start -= inChart.GridStepChart
                    }else{
                        break
                    }
                }
            }
            for{
                if start <= candleMax {
                    if start > candleMin {
                        drawValues = append(drawValues, start)
                    }
                    start += inChart.GridStepChart
                }else{
                    break
                }
            }
        }
        drawValues = append(drawValues, firstOpen)
        for i:= 0; i < len(drawValues); i++ {
            start := drawValues[i]
            hAxisY := GetChartY(chart, 0, start)
            if hAxisY < 1 || hAxisY > candleDivHeight {
                continue
            }
            paint.DrawLine(inChart.GridColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth, hAxisY, chart.Size.Cx - inChart.RightVScaleWidth, hAxisY)
            paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth - 8, hAxisY, inChart.LeftVScaleWidth, hAxisY)
            paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, chart.Size.Cx - inChart.RightVScaleWidth, hAxisY, chart.Size.Cx - inChart.RightVScaleWidth + 8, hAxisY)
            
            DrawText := ToFixed(start, inChart.CandleDigit)
            tSize := paint.TextSize(DrawText, chart.Font)
            if isTrend {
                diffRange := ((start - firstOpen) / firstOpen * 100)
                diffRangeStr := ToFixed(diffRange, 2) + "%"
                if diffRange >= 0 {
                    paint.DrawText(diffRangeStr, inChart.UpColor, chart.Font, chart.Size.Cx - inChart.RightVScaleWidth + 10, hAxisY - tSize.Cy / 2)
                } else {
                    paint.DrawText(diffRangeStr,inChart.DownColor, chart.Font, chart.Size.Cx - inChart.RightVScaleWidth + 10, hAxisY - tSize.Cy / 2)
                }
            } else {
                paint.DrawText(DrawText, chart.TextColor, chart.Font, chart.Size.Cx - inChart.RightVScaleWidth + 10, hAxisY - tSize.Cy / 2)
            }
            paint.DrawText(DrawText, chart.TextColor, chart.Font, inChart.LeftVScaleWidth - tSize.Cx - 10, hAxisY - tSize.Cy / 2)
        }
        topPoint = CreatePoint(0, candleDivHeight + 10)
        bottomPoint = CreatePoint(0, candleDivHeight + volDivHeight - 10)
        volMax := GetChartValue(chart, topPoint)
        volMin := GetChartValue(chart, bottomPoint)
        ChartGridScale(chart, volMin, volMax, int((volDivHeight - inChart.VolPaddingTop - inChart.VolPaddingBottom) / 2), inChart.VScaleDistance, inChart.VScaleDistance / 2, int((volDivHeight - inChart.VolPaddingTop - inChart.VolPaddingBottom) / inChart.VScaleDistance))
        if inChart.GridStepChart > 0 {
            start := 0.0
            if volMin >= 0 {
                for{
                    if start + inChart.GridStepChart < volMin {
                        start += inChart.GridStepChart
                    }else{
                        break
                    }
                }
            } else {
                for{
                    if start - inChart.GridStepChart > volMin {
                        start -= inChart.GridStepChart
                    }else{
                        break
                    }
                }
            }
            for{
                if start <= volMax {
                    if start > volMin {
                        hAxisY := GetChartY(chart, 1, start)
                        if hAxisY < candleDivHeight || hAxisY > candleDivHeight + volDivHeight {
                            continue
                        }
                        paint.DrawLine(inChart.GridColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth, hAxisY, chart.Size.Cx - inChart.RightVScaleWidth, hAxisY)
                        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth - 8, hAxisY, inChart.LeftVScaleWidth, hAxisY)
                        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, chart.Size.Cx - inChart.RightVScaleWidth, hAxisY, chart.Size.Cx - inChart.RightVScaleWidth + 8, hAxisY)
                        DrawText := ToFixed((start / float64(inChart.Magnitude)), inChart.VolDigit)
                        tSize := paint.TextSize(DrawText, chart.Font)
                        paint.DrawText(DrawText, chart.TextColor, chart.Font, chart.Size.Cx - inChart.RightVScaleWidth + 10, hAxisY - tSize.Cy / 2)
                        paint.DrawText(DrawText, chart.TextColor, chart.Font, inChart.LeftVScaleWidth - tSize.Cx - 10, hAxisY - tSize.Cy / 2)
                    }
                    start += inChart.GridStepChart
                }else{
                    break
                }
            }
        }
    }
    if indDivHeight > 0 {
        topPoint := CreatePoint(0, candleDivHeight + volDivHeight + 10)
        bottomPoint := CreatePoint(0, candleDivHeight + volDivHeight + indDivHeight - 10)
        indMax := GetChartValue(chart, topPoint)
        indMin := GetChartValue(chart, bottomPoint)
        ChartGridScale(chart, indMin, indMax, int((indDivHeight - inChart.IndPaddingTop - inChart.IndPaddingBottom) / 2), inChart.VScaleDistance, inChart.VScaleDistance / 2, int((indDivHeight - inChart.IndPaddingTop - inChart.IndPaddingBottom) / inChart.VScaleDistance))
        if inChart.GridStepChart > 0 {
            start := 0.0
            if indMin >= 0 {
                for{
                    if start + inChart.GridStepChart < indMin {
                        start += inChart.GridStepChart
                    }else{
                        break
                    }
                }
            } else {
                for{
                    if start - inChart.GridStepChart > indMin {
                        start -= inChart.GridStepChart
                    }else{
                        break
                    }
                }
            }
            for{
                if start <= indMax {
                    if start > indMin {
                        hAxisY := GetChartY(chart, 2, start)
                        if hAxisY < candleDivHeight + volDivHeight || hAxisY > candleDivHeight + volDivHeight + indDivHeight {
                            continue
                        }
                        paint.DrawLine(inChart.GridColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth, hAxisY, chart.Size.Cx - inChart.RightVScaleWidth, hAxisY)
                        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth - 8, hAxisY, inChart.LeftVScaleWidth, hAxisY)
                        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, chart.Size.Cx - inChart.RightVScaleWidth, hAxisY, chart.Size.Cx - inChart.RightVScaleWidth + 8, hAxisY)
                        DrawText := ToFixed(start, inChart.IndDigit)
                        tSize := paint.TextSize(DrawText, chart.Font)
                        paint.DrawText(DrawText, chart.TextColor, chart.Font, chart.Size.Cx - inChart.RightVScaleWidth + 10, hAxisY - tSize.Cy / 2)
                        paint.DrawText(DrawText, chart.TextColor, chart.Font, inChart.LeftVScaleWidth - tSize.Cx - 10, hAxisY - tSize.Cy / 2)
                    }
                    start += inChart.GridStepChart
                }else{
                    break
                }
            }
        }
    }
    if indDivHeight2 > 0 {
        topPoint = CreatePoint(0, candleDivHeight + volDivHeight + indDivHeight + 10)
        bottomPoint = CreatePoint(0, candleDivHeight + volDivHeight + indDivHeight + indDivHeight2 - 10)
        indMax2 := GetChartValue(chart, topPoint)
        indMin2 := GetChartValue(chart, bottomPoint)
        ChartGridScale(chart, indMin2, indMax2, int((indDivHeight2 - inChart.IndPaddingTop2 - inChart.IndPaddingBottom2) / 2), inChart.VScaleDistance, inChart.VScaleDistance / 2, int((indDivHeight2 - inChart.IndPaddingTop2 - inChart.IndPaddingBottom2) / inChart.VScaleDistance))
        if inChart.GridStepChart > 0 {
            start := 0.0
            if indMin2 >= 0 {
                for{
                    if start + inChart.GridStepChart < indMin2 {
                        start += inChart.GridStepChart
                    }else{
                        break
                    }
                }
            } else {
                for{
                    if start - inChart.GridStepChart > indMin2 {
                        start -= inChart.GridStepChart
                    }else{
                        break
                    }
                }
            }
            for{
                if start <= indMax2 {
                    if start > indMin2 {
                        hAxisY := GetChartY(chart, 3, start)
                        if hAxisY < candleDivHeight + volDivHeight + indDivHeight || hAxisY > candleDivHeight + volDivHeight + indDivHeight + indDivHeight2 {
                            continue
                        }
                        paint.DrawLine(inChart.GridColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth, hAxisY, chart.Size.Cx - inChart.RightVScaleWidth, hAxisY)
                        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth - 8, hAxisY, inChart.LeftVScaleWidth, hAxisY)
                        paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, chart.Size.Cx - inChart.RightVScaleWidth, hAxisY, chart.Size.Cx - inChart.RightVScaleWidth + 8, hAxisY)
                        DrawText := ToFixed(start, inChart.IndDigit)
                        tSize := paint.TextSize(DrawText, chart.Font)
                        paint.DrawText(DrawText, chart.TextColor,chart.Font, chart.Size.Cx - inChart.RightVScaleWidth + 10, hAxisY - tSize.Cy / 2)
                        paint.DrawText(DrawText, chart.TextColor,chart.Font, inChart.LeftVScaleWidth - tSize.Cx - 10, hAxisY - tSize.Cy / 2)
                    }
                    start += inChart.GridStepChart
                }else{
                    break
                }
            }
        }
    }
    if paint.OnPaintChartHScale != nil{
        paint.OnPaintChartHScale(chart, paint, clipRect)
    }else{
        if len(inChart.Data) > 0 && inChart.HScaleHeight > 0 {
            dLeft := inChart.LeftVScaleWidth + 10
            i := inChart.FirstVisibleIndex
            for i = inChart.FirstVisibleIndex; i <= inChart.LastVisibleIndex; i++ {
                tm := time.Unix(int64(inChart.Data[i].Date / 1000), 0)
                xText := ""
                if len(inChart.HScaleFormat) > 0 {
                    xText = tm.Format(inChart.HScaleFormat)
                } else {
                    if inChart.Cycle == "day"{
                        xText = tm.Format("2006-01-02")
                    } else if inChart.Cycle == "minute" {
                        xText = tm.Format("2006/01/02 15:04")
                    } else if inChart.Cycle == "trend" {
                        xText = tm.Format("15:04")
                    }else if inChart.Cycle == "second" {
                        xText = tm.Format("15:04:05")
                    }else if inChart.Cycle == "tick"{
                        xText = ConvertIntToStr(i + 1)
                    }
                }
                tSize := paint.TextSize(xText, chart.Font)
                x := GetChartX(chart, i)
                dx := x - tSize.Cx / 2
                if dx > dLeft && dx < chart.Size.Cx - inChart.RightVScaleWidth - 10 {
                    paint.DrawLine(inChart.ScaleColor, inChart.LineWidthChart, 0, x, chart.Size.Cy - inChart.HScaleHeight, x, chart.Size.Cy - inChart.HScaleHeight + 8)
                    paint.DrawText(xText, chart.TextColor, chart.Font, dx, chart.Size.Cy - inChart.HScaleHeight + 8  - tSize.Cy / 2 + 7)
                    i = i + int((tSize.Cx + inChart.HScaleTextDistance) / inChart.HScalePixel) + 1
                }
            }
        }
    }
}

/*
* 绘制十字线
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawChartCrossLine(chart *FCView, paint *FCPaint, clipRect FCRect) {
    inChart := chart.GetChart()
    if len(inChart.Data) == 0 {
        return
    }
    candleDivHeight := GetCandleDivHeight(chart)
    volDivHeight := GetVolDivHeight(chart)
    indDivHeight := GetIndDivHeight(chart)
    indDivHeight2 := GetIndDivHeight2(chart)
    crossLineIndex := inChart.CrossStopIndex
    if crossLineIndex == -1 || !inChart.ShowCrossLine{
        crossLineIndex = inChart.LastVisibleIndex
    }
    if volDivHeight > 0 {
        var drawTitles []string
        var drawColors []string
        drawTitles = append(drawTitles, "VOL " + ToFixed(inChart.Data[crossLineIndex].Volume, inChart.VolDigit))
        drawColors = append(drawColors, chart.TextColor)
        if len(inChart.Shapes)  > 0 {
            for i:= 0; i < len(inChart.Shapes); i++ {
                shape := inChart.Shapes[i]
                if shape.DivIndex == 1 {
                    if len(shape.Title) > 0 {
                        if shape.ShapeType == "bar" && shape.Style == "2color" {
                            drawTitles = append(drawTitles, shape.Title + " " + ToFixed(shape.Datas[crossLineIndex], inChart.VolDigit))
                            drawColors = append(drawColors, shape.Color2)
                        } else {
                            if shape.ShapeType != "text" {
                                drawTitles = append(drawTitles, shape.Title + " " + ToFixed(shape.Datas[crossLineIndex], inChart.VolDigit))
                                drawColors = append(drawColors, shape.Color)
                                if len(shape.Datas2) > 0 {
                                    drawTitles = append(drawTitles, shape.Title2 + " " + ToFixed(shape.Datas2[crossLineIndex], inChart.VolDigit))
                                    drawColors = append(drawColors, shape.Color2)
                                }
                            }
                        }
                    }
                }
            }
        }
        iLeft := inChart.LeftVScaleWidth + 5
        for i:= 0; i < len(drawTitles); i++ {
            tSize := paint.TextSize(drawTitles[i], chart.Font)
            paint.DrawText(drawTitles[i], drawColors[i], chart.Font, iLeft, candleDivHeight + 5)
            iLeft += tSize.Cx + 5
        }
    }
    //上面显示数据  高开低收
    if inChart.Cycle == "trend" {
        var drawTitles []string
        var drawColors []string
        drawTitles = append(drawTitles, "CLOSE " + ToFixed(inChart.Data[crossLineIndex].Close, inChart.CandleDigit))
        drawColors = append(drawColors, chart.TextColor)
        if len(inChart.Shapes) > 0 {
            for i:= 0; i < len(inChart.Shapes); i++ {
                shape := inChart.Shapes[i]
                if shape.DivIndex == 0 {
                    if len(shape.Title) > 0 {
                        if shape.ShapeType == "bar" && shape.Style == "2color" {
                            drawTitles = append(drawTitles, shape.Title + " " + ToFixed(shape.Datas[crossLineIndex], inChart.CandleDigit))
                            drawColors = append(drawColors, shape.Color2)
                        } else {
                            if shape.ShapeType != "text" {
                                drawTitles = append(drawTitles, shape.Title + " " + ToFixed(shape.Datas[crossLineIndex], inChart.CandleDigit))
                                drawColors = append(drawColors, shape.Color)
                                if len(shape.Datas2) > 0 {
                                    drawTitles = append(drawTitles, shape.Title2 + " " + ToFixed(shape.Datas2[crossLineIndex], inChart.CandleDigit))
                                    drawColors = append(drawColors, shape.Color2)
                                }
                            }
                        }
                    }
                }
            }
        }
        iLeft := inChart.LeftVScaleWidth + 5
        for i:= 0; i < len(drawTitles); i++ {
            tSize := paint.TextSize(drawTitles[i], chart.Font)
            paint.DrawText(drawTitles[i], drawColors[i], chart.Font, iLeft, 5)
            iLeft += tSize.Cx + 5
        }
    } else {
        var drawTitles []string
        var drawColors []string
        if inChart.MainIndicator == "MA" {
            if len(inChart.Ma5) > 0 {
                drawTitles = append(drawTitles, "MA5 " + ToFixed(inChart.Ma5[crossLineIndex], inChart.CandleDigit))
            } else {
                drawTitles = append(drawTitles, "MA5")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[0])
            if len(inChart.Ma10) > 0 {
                drawTitles = append(drawTitles, "MA10 " + ToFixed(inChart.Ma10[crossLineIndex], inChart.CandleDigit))
            } else {
                drawTitles = append(drawTitles, "MA10")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[1])
            if len(inChart.Ma20) > 0 {
                drawTitles = append(drawTitles, "MA20 " + ToFixed(inChart.Ma20[crossLineIndex], inChart.CandleDigit))

            } else {
                drawTitles = append(drawTitles, "MA20")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[2])
            if len(inChart.Ma30) > 0 {
                drawTitles = append(drawTitles, "MA30 " + ToFixed(inChart.Ma30[crossLineIndex], inChart.CandleDigit))
            } else {
                drawTitles = append(drawTitles, "MA30")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[5])
            if len(inChart.Ma120) > 0 {
                drawTitles = append(drawTitles, "MA120 " + ToFixed(inChart.Ma120[crossLineIndex], inChart.CandleDigit))

            } else {
                drawTitles = append(drawTitles, "MA120")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[4])
            if len(inChart.Ma250) > 0 {
                drawTitles = append(drawTitles, "MA250 " + ToFixed(inChart.Ma250[crossLineIndex], inChart.CandleDigit))
            } else {
                drawTitles = append(drawTitles, "MA250")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[3])
        } else if inChart.MainIndicator == "BOLL" {
            if len(inChart.BollMid) > 0 {
                drawTitles = append(drawTitles, "MID " + ToFixed(inChart.BollMid[crossLineIndex], inChart.CandleDigit))
            } else {
                drawTitles = append(drawTitles, "MID")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[0])
            if len(inChart.BollUp) > 0 {
                drawTitles = append(drawTitles, "UP " + ToFixed(inChart.BollUp[crossLineIndex], inChart.CandleDigit))
            } else {
                drawTitles = append(drawTitles, "UP")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[1])
            if len(inChart.BollDown) > 0 {
                drawTitles = append(drawTitles, "LOW " + ToFixed(inChart.BollDown[crossLineIndex], inChart.CandleDigit))
            } else {
                drawTitles = append(drawTitles, "LOW")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[2])
        }
        if len(inChart.Shapes) > 0 {
            for i:= 0; i < len(inChart.Shapes); i++ {
                shape := inChart.Shapes[i]
                if shape.DivIndex == 0 {
                    if len(shape.Title) > 0 {
                        if shape.ShapeType == "bar" && shape.Style == "2color" {
                            drawTitles = append(drawTitles, shape.Title + " " + ToFixed(shape.Datas[crossLineIndex], inChart.CandleDigit))
                            drawColors = append(drawColors, shape.Color2)
                        } else {
                            if shape.ShapeType != "text" {
                                drawTitles = append(drawTitles, shape.Title + " " + ToFixed(shape.Datas[crossLineIndex], inChart.CandleDigit))
                                drawColors = append(drawColors, shape.Color)
                                if len(shape.Datas2) > 0 {
                                    drawTitles = append(drawTitles, shape.Title2 + " " + ToFixed(shape.Datas2[crossLineIndex], inChart.CandleDigit))
                                    drawColors = append(drawColors, shape.Color2)
                                }
                            }
                        }
                    }
                }
            }
        }
        iLeft := inChart.LeftVScaleWidth + 5
        for i:= 0; i < len(drawTitles); i++ {
            tSize := paint.TextSize(drawTitles[i], chart.Font)
            paint.DrawText(drawTitles[i], drawColors[i], chart.Font, iLeft, 5)
            iLeft += tSize.Cx + 5
        }
    }
    if indDivHeight > 0 {
        var drawTitles []string
        var drawColors []string
        if inChart.ShowIndicator == "MACD" {
            if len(inChart.Alldifarr) > 0 {
                drawTitles = append(drawTitles, "DIF " + ToFixed(inChart.Alldifarr[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "DIF")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[0])
            if len(inChart.Alldeaarr) > 0 {
                drawTitles = append(drawTitles, "DEA " + ToFixed(inChart.Alldeaarr[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "DEA")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[1])
            if len(inChart.Allmacdarr) > 0 {
                drawTitles = append(drawTitles, "MACD " + ToFixed(inChart.Allmacdarr[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "MACD")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[4])
        } else if inChart.ShowIndicator == "KDJ" {
            if len(inChart.KdjK) > 0 {
                drawTitles = append(drawTitles, "K " + ToFixed(inChart.KdjK[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "K")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[0])
            if len(inChart.KdjD) > 0 {
                drawTitles = append(drawTitles, "D " + ToFixed(inChart.KdjD[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "D")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[1])
            if len(inChart.KdjJ) > 0 {
                drawTitles = append(drawTitles, "J " + ToFixed(inChart.KdjJ[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "J")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[2])
        } else if inChart.ShowIndicator == "RSI" {
            if len(inChart.Rsi1) > 0 {
                drawTitles = append(drawTitles, "RSI6 " + ToFixed(inChart.Rsi1[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "RSI6")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[5])
            if len(inChart.Rsi2) > 0 {
                drawTitles = append(drawTitles, "RSI12 " + ToFixed(inChart.Rsi2[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "RSI12")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[1])
            if (len(inChart.Rsi3) > 0) {
                drawTitles = append(drawTitles, "RSI24 " + ToFixed(inChart.Rsi3[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "RSI24")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[2])
        }else if (inChart.ShowIndicator == "BIAS") {
            if len(inChart.Bias1) > 0{
                drawTitles = append(drawTitles, "BIAS6 " + ToFixed(inChart.Bias1[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "BIAS6")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[5])
            if len(inChart.Bias2) > 0 {
                drawTitles = append(drawTitles, "BIAS12 " + ToFixed(inChart.Bias2[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "BIAS12")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[1])
            if len(inChart.Bias3) > 0 {
                drawTitles = append(drawTitles, "BIAS24 " + ToFixed(inChart.Bias3[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "BIAS24")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[2])
        } else if inChart.ShowIndicator == "ROC" {
            if len(inChart.Roc) > 0 {
                drawTitles = append(drawTitles, "ROC " + ToFixed(inChart.Roc[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "ROC")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[0])
            if len(inChart.RocMa) > 0 {
                drawTitles = append(drawTitles, "ROCMA " + ToFixed(inChart.RocMa[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "ROCMA")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[1])
        }else if inChart.ShowIndicator == "WR" {
            if len(inChart.Wr1) > 0 {
                drawTitles = append(drawTitles, "WR5 " + ToFixed(inChart.Wr1[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "WR5")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[0])
            if len(inChart.Wr2) > 0 {
                drawTitles = append(drawTitles, "WR10 " + ToFixed(inChart.Wr2[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "WR10")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[1])
        } else if inChart.ShowIndicator == "CCI" {
            if len(inChart.Cci) > 0 {
                drawTitles = append(drawTitles, "CCI " + ToFixed(inChart.Cci[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "CCI")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[0])
        } else if inChart.ShowIndicator == "BBI" {
            if len(inChart.Bbi) > 0 {
                drawTitles = append(drawTitles, "BBI " + ToFixed(inChart.Bbi[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "BBI")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[0])
        } else if inChart.ShowIndicator == "TRIX" {
            if len(inChart.Trix) > 0 {
                drawTitles = append(drawTitles, "TRIX " + ToFixed(inChart.Trix[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "TRIX")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[0])
            if len(inChart.TrixMa) > 0 {
                drawTitles = append(drawTitles, "TRIXMA " + ToFixed(inChart.TrixMa[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "TRIXMA")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[1])
        } else if inChart.ShowIndicator == "DMA" {
            if len(inChart.Dma1) > 0 {
                drawTitles = append(drawTitles, "MA10 " + ToFixed(inChart.Dma1[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "MA10")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[0])
            if len(inChart.Dma2) > 0 {
                drawTitles = append(drawTitles, "MA50 " + ToFixed(inChart.Dma2[crossLineIndex], inChart.IndDigit))
            } else {
                drawTitles = append(drawTitles, "MA50")
            }
            drawColors = append(drawColors, inChart.IndicatorColors[1])
        }
        if len(inChart.Shapes) > 0 {
            for i:= 0; i < len(inChart.Shapes); i++ {
                shape := inChart.Shapes[i]
                if shape.DivIndex == 2 {
                    if len(shape.Title) > 0 {
                        if shape.ShapeType == "bar" && shape.Style == "2color" {
                            drawTitles = append(drawTitles, shape.Title + " " + ToFixed(shape.Datas[crossLineIndex], inChart.IndDigit))
                            drawColors = append(drawColors, shape.Color2)
                        } else {
                            if shape.ShapeType != "text" {
                                drawTitles = append(drawTitles, shape.Title + " " + ToFixed(shape.Datas[crossLineIndex], inChart.IndDigit))
                                drawColors = append(drawColors, shape.Color)
                                if len(shape.Datas2) > 0 {
                                    drawTitles = append(drawTitles, shape.Title2 + " " + ToFixed(shape.Datas2[crossLineIndex], inChart.IndDigit))
                                    drawColors = append(drawColors, shape.Color2)
                                }
                            }
                        }
                    }
                }
            }
        }
        iLeft := inChart.LeftVScaleWidth + 5
        for i:= 0; i < len(drawTitles); i++ {
            tSize := paint.TextSize(drawTitles[i], chart.Font)
            paint.DrawText(drawTitles[i], drawColors[i], chart.Font, iLeft, candleDivHeight + volDivHeight + 5)
            iLeft += tSize.Cx + 5
        }
    }
    if indDivHeight2 > 0 {
        var drawTitles []string
        var drawColors []string
        if len(inChart.Shapes) > 0 {
            for i:= 0; i < len(inChart.Shapes); i++ {
                shape := inChart.Shapes[i]
                if shape.DivIndex == 3 {
                    if len(shape.Title) > 0 {
                        if shape.ShapeType == "bar" && shape.Style == "2color" {
                            drawTitles = append(drawTitles, shape.Title + " " + ToFixed(shape.Datas[crossLineIndex], inChart.IndDigit2))
                            drawColors = append(drawColors, shape.Color2)
                        } else {
                            if shape.ShapeType != "text" {
                                drawTitles = append(drawTitles, shape.Title + " " + ToFixed(shape.Datas[crossLineIndex], inChart.IndDigit2))
                                drawColors = append(drawColors, shape.Color)
                                if len(shape.Datas2) > 0 {
                                    drawTitles = append(drawTitles, shape.Title2 + " " + ToFixed(shape.Datas2[crossLineIndex], inChart.IndDigit2))
                                    drawColors = append(drawColors, shape.Color2)
                                }
                            }
                        }
                    }
                }
            }
        }
        if len(drawTitles) > 0 {
            iLeft := inChart.LeftVScaleWidth + 5
            for i:= 0; i < len(drawTitles); i++ {
                tSize := paint.TextSize(drawTitles[i], chart.Font)
                paint.DrawText(drawTitles[i], drawColors[i], chart.Font, iLeft, candleDivHeight + volDivHeight + indDivHeight + 5 + tSize.Cy / 2)
                iLeft += tSize.Cx + 5
            }
        }
    }

    if inChart.ShowCrossLine {
        rightText := ""
        if inChart.TouchPosition.Y < candleDivHeight {
            rightText = ToFixed(GetChartValue(chart, inChart.TouchPosition), inChart.CandleDigit)
        }else if inChart.TouchPosition.Y > candleDivHeight && inChart.TouchPosition.Y < candleDivHeight + volDivHeight {
            rightText = ToFixed(GetChartValue(chart, inChart.TouchPosition), inChart.VolDigit)
        } else if inChart.TouchPosition.Y > candleDivHeight + volDivHeight && inChart.TouchPosition.Y < candleDivHeight + volDivHeight + indDivHeight {
            rightText = ToFixed(GetChartValue(chart, inChart.TouchPosition), inChart.IndDigit)
        } else if inChart.TouchPosition.Y > candleDivHeight + volDivHeight + indDivHeight && inChart.TouchPosition.Y < candleDivHeight + volDivHeight + indDivHeight + indDivHeight2 {
            rightText = ToFixed(GetChartValue(chart, inChart.TouchPosition), inChart.IndDigit2)
        }

        drawY := inChart.TouchPosition.Y
        if drawY > chart.Size.Cy - inChart.HScaleHeight {
            drawY = chart.Size.Cy - inChart.HScaleHeight
        }
        tSize := paint.TextSize(rightText, chart.Font)
        if inChart.LeftVScaleWidth > 0{
            paint.FillRect(inChart.CrossTipColor, inChart.LeftVScaleWidth - tSize.Cx, drawY - tSize.Cy / 2 - 4, inChart.LeftVScaleWidth, drawY + tSize.Cy / 2 + 3)
            paint.DrawText(rightText, chart.TextColor, chart.Font, inChart.LeftVScaleWidth - tSize.Cx, drawY - tSize.Cy / 2)
        }
        if inChart.RightVScaleWidth > 0 {
            paint.FillRect(inChart.CrossTipColor, chart.Size.Cx - inChart.RightVScaleWidth, drawY - tSize.Cy / 2 - 4, chart.Size.Cx - inChart.RightVScaleWidth + tSize.Cx, drawY + tSize.Cy / 2 + 3)
            paint.DrawText(rightText, chart.TextColor, chart.Font, chart.Size.Cx - inChart.RightVScaleWidth, drawY - tSize.Cy / 2)
        }
        //绘制十字线
        drawX := GetChartX(chart, inChart.CrossStopIndex)
		if chart.GetPaint().GetTouchDownView() == chart{
			drawX = inChart.TouchPosition.X
		}
        if drawX < inChart.LeftVScaleWidth {
            drawX = inChart.LeftVScaleWidth
        }
        if drawX > chart.Size.Cx - inChart.RightVScaleWidth {
            drawX = chart.Size.Cx - inChart.RightVScaleWidth
        }
        sPlot := inChart.GetSelectedPlot()
        if !sPlot.IsNotEmpty && inChart.SelectShape == "" {
            paint.DrawLine(inChart.CrossLineColor, inChart.LineWidthChart, 0, inChart.LeftVScaleWidth, drawY, chart.Size.Cx - inChart.RightVScaleWidth, drawY)
            paint.DrawLine(inChart.CrossLineColor, inChart.LineWidthChart, 0, drawX, 0, drawX, chart.Size.Cy - inChart.HScaleHeight)
        }
        if inChart.CrossStopIndex != -1 {
            tm := time.Unix(int64(inChart.Data[inChart.CrossStopIndex].Date / 1000), 0)
            xText := ""
            if len(inChart.HScaleFormat) > 0{
                xText = tm.Format(inChart.HScaleFormat)
			} else {
				if inChart.Cycle == "day" {
					xText = tm.Format("2006-01-02")
				} else if inChart.Cycle == "minute" {
					xText = tm.Format("2006/01/02 15:04")
				} else if inChart.Cycle == "trend" {
					xText = tm.Format("15:04")
				}else if inChart.Cycle == "second" {
					xText = tm.Format("15:04:05")
				}else if inChart.Cycle == "tick" {
					xText = ConvertIntToStr(inChart.CrossStopIndex + 1)
				}
			}
            xSize := paint.TextSize(xText, chart.Font)
            paint.FillRect(inChart.CrossTipColor, drawX - xSize.Cx / 2 - 2, candleDivHeight + volDivHeight + indDivHeight, drawX + xSize.Cx / 2 + 2, candleDivHeight + volDivHeight + indDivHeight + xSize.Cy + 6)
            paint.DrawText(xText, chart.TextColor, chart.Font, drawX - xSize.Cx / 2, candleDivHeight + volDivHeight + indDivHeight + 3)
        }
    }
}

/*
* 计算最大最小值
* chart:图表
*/
func CalculateChartMaxMin(chart *FCView) {
    inChart := chart.GetChart()
    inChart.CandleMax = 0
    inChart.CandleMin = 0
    inChart.VolMax = 0
    inChart.VolMin = 0
    inChart.IndMin = 0
    inChart.IndMin = 0
    load1 := false
    load2 := false
    load3 := false
    load4 := false
    isTrend := false
    if inChart.Cycle == "trend"{
        isTrend = true
    }
    firstOpen := 0.0
    if len(inChart.Data) > 0 {
        lastValidIndex := inChart.LastVisibleIndex
        if inChart.LastValidIndex != -1 {
            lastValidIndex = inChart.LastValidIndex
        }
        for i := inChart.FirstVisibleIndex; i <= lastValidIndex; i++ {
            if i == inChart.FirstVisibleIndex {
                if isTrend {
                    inChart.CandleMax = inChart.Data[i].Close
                    inChart.CandleMin = inChart.Data[i].Close
                    firstOpen = inChart.Data[i].Close
                } else {
                    inChart.CandleMax = inChart.Data[i].High
                    inChart.CandleMin = inChart.Data[i].Low
                }
                inChart.VolMax = inChart.Data[i].Volume
                load1 = true
                load2 = true
                if inChart.ShowIndicator == "MACD" {
                    inChart.IndMax = inChart.Alldifarr[i]
                    inChart.IndMin = inChart.Alldifarr[i]
                    load3 = true
                }else if inChart.ShowIndicator == "KDJ" {
                    inChart.IndMax = inChart.KdjK[i]
                    inChart.IndMin = inChart.KdjK[i]
                    load3 = true
                }else if inChart.ShowIndicator == "RSI" {
                    inChart.IndMax = inChart.Rsi1[i]
                    inChart.IndMin = inChart.Rsi1[i]
                    load3 = true
                }else if inChart.ShowIndicator == "BIAS" {
                    inChart.IndMax = inChart.Bias1[i]
                    inChart.IndMin = inChart.Bias1[i]
                    load3 = true
                }else if inChart.ShowIndicator == "ROC" {
                    inChart.IndMax = inChart.Roc[i]
                    inChart.IndMin = inChart.Roc[i]
                    load3 = true
                }else if inChart.ShowIndicator == "WR" {
                    inChart.IndMax = inChart.Wr1[i]
                    inChart.IndMin = inChart.Wr1[i]
                    load3 = true
                } else if inChart.ShowIndicator == "CCI" {
                    inChart.IndMax = inChart.Cci[i]
                    inChart.IndMin = inChart.Cci[i]
                    load3 = true
                } else if inChart.ShowIndicator == "BBI" {
                    inChart.IndMax = inChart.Bbi[i]
                    inChart.IndMin = inChart.Bbi[i]
                    load3 = true
                }else if inChart.ShowIndicator == "TRIX" {
                    inChart.IndMax = inChart.Trix[i]
                    inChart.IndMin = inChart.Trix[i]
                    load3 = true
                }else if inChart.ShowIndicator == "DMA" {
                    inChart.IndMax = inChart.Dma1[i]
                    inChart.IndMin = inChart.Dma1[i]
                    load3 = true
                }
            }else {
                if isTrend{
                    if inChart.CandleMax < inChart.Data[i].Close {
                        inChart.CandleMax = inChart.Data[i].Close
                    }
                    if inChart.CandleMin > inChart.Data[i].Close{
                        inChart.CandleMin = inChart.Data[i].Close
                    }
                } else {
                    if inChart.CandleMax < inChart.Data[i].High {
                        inChart.CandleMax = inChart.Data[i].High
                    }
                    if inChart.CandleMin > inChart.Data[i].Low{
                        inChart.CandleMin = inChart.Data[i].Low
                    }
                }
                if inChart.VolMax < inChart.Data[i].Volume {
                    inChart.VolMax = inChart.Data[i].Volume
                }
            }
            if inChart.ShowIndicator == "MACD" {
                if inChart.IndMax < inChart.Alldifarr[i] {
                    inChart.IndMax = inChart.Alldifarr[i]
                }
                if inChart.IndMax < inChart.Alldeaarr[i] {
                    inChart.IndMax = inChart.Alldeaarr[i]
                }
                if inChart.IndMax < inChart.Allmacdarr[i] {
                    inChart.IndMax = inChart.Allmacdarr[i]
                }
                if inChart.IndMin > inChart.Alldifarr[i] {
                    inChart.IndMin = inChart.Alldifarr[i]
                }
                if inChart.IndMin > inChart.Alldeaarr[i] {
                    inChart.IndMin = inChart.Alldeaarr[i]
                }
                if inChart.IndMin > inChart.Allmacdarr[i] {
                    inChart.IndMin = inChart.Allmacdarr[i]
                }
            } else if inChart.ShowIndicator == "KDJ" {
                if inChart.IndMax < inChart.KdjK[i] {
                    inChart.IndMax = inChart.KdjK[i]
                }
                if inChart.IndMax < inChart.KdjD[i] {
                    inChart.IndMax = inChart.KdjD[i]
                }
                if inChart.IndMax < inChart.KdjJ[i] {
                    inChart.IndMax = inChart.KdjJ[i]
                }
                if inChart.IndMin > inChart.KdjK[i] {
                    inChart.IndMin = inChart.KdjK[i]
                }
                if inChart.IndMin > inChart.KdjD[i] {
                    inChart.IndMin = inChart.KdjD[i]
                }
                if inChart.IndMin > inChart.KdjJ[i] {
                    inChart.IndMin = inChart.KdjJ[i]
                }
            } else if inChart.ShowIndicator == "RSI" {
                if inChart.IndMax < inChart.Rsi1[i] {
                    inChart.IndMax = inChart.Rsi1[i]
                }
                if inChart.IndMax < inChart.Rsi2[i] {
                    inChart.IndMax = inChart.Rsi2[i]
                }
                if inChart.IndMax < inChart.Rsi3[i] {
                    inChart.IndMax = inChart.Rsi3[i]
                }
                if inChart.IndMin > inChart.Rsi1[i] {
                    inChart.IndMin = inChart.Rsi1[i]
                }
                if inChart.IndMin > inChart.Rsi2[i] {
                    inChart.IndMin = inChart.Rsi2[i]
                }
                if inChart.IndMin > inChart.Rsi3[i] {
                    inChart.IndMin = inChart.Rsi3[i]
                }
            } else if inChart.ShowIndicator == "BIAS" {
                if inChart.IndMax < inChart.Bias1[i]{
                    inChart.IndMax = inChart.Bias1[i]
                }
                if inChart.IndMax < inChart.Bias2[i] {
                    inChart.IndMax = inChart.Bias2[i]
                }
                if inChart.IndMax < inChart.Bias3[i] {
                    inChart.IndMax = inChart.Bias3[i]
                }
                if inChart.IndMin > inChart.Bias1[i] {
                    inChart.IndMin = inChart.Bias1[i]
                }
                if inChart.IndMin > inChart.Bias2[i] {
                    inChart.IndMin = inChart.Bias2[i]
                }
                if inChart.IndMin > inChart.Bias3[i] {
                    inChart.IndMin = inChart.Bias3[i]
                }
            } else if inChart.ShowIndicator == "ROC" {
                if inChart.IndMax < inChart.Roc[i]{
                    inChart.IndMax = inChart.Roc[i]
                }
                if inChart.IndMax < inChart.RocMa[i] {
                    inChart.IndMax = inChart.RocMa[i]
                }
                if inChart.IndMin > inChart.Roc[i] {
                    inChart.IndMin = inChart.Roc[i]
                }
                if inChart.IndMin > inChart.RocMa[i] {
                    inChart.IndMin = inChart.RocMa[i]
                }
            }else if inChart.ShowIndicator == "WR" {
                if inChart.IndMax < inChart.Wr1[i] {
                    inChart.IndMax = inChart.Wr1[i]
                }
                if inChart.IndMax < inChart.Wr2[i] {
                    inChart.IndMax = inChart.Wr2[i]
                }
                if inChart.IndMin > inChart.Wr1[i] {
                    inChart.IndMin = inChart.Wr1[i]
                }
                if inChart.IndMin > inChart.Wr2[i] {
                    inChart.IndMin = inChart.Wr2[i]
                }
            } else if inChart.ShowIndicator == "CCI" {
                if inChart.IndMax < inChart.Cci[i] {
                    inChart.IndMax = inChart.Cci[i]
                }
                if inChart.IndMin > inChart.Cci[i] {
                    inChart.IndMin = inChart.Cci[i]
                }
            } else if inChart.ShowIndicator == "BBI" {
                if inChart.IndMax < inChart.Bbi[i] {
                    inChart.IndMax = inChart.Bbi[i]
                }
                if inChart.IndMin > inChart.Bbi[i] {
                    inChart.IndMin = inChart.Bbi[i]
                }
            } else if inChart.ShowIndicator == "TRIX" {
                if inChart.IndMax < inChart.Trix[i] {
                    inChart.IndMax = inChart.Trix[i]
                }
                if inChart.IndMax < inChart.TrixMa[i] {
                    inChart.IndMax = inChart.TrixMa[i]
                }
                if inChart.IndMin > inChart.Trix[i]{
                    inChart.IndMin = inChart.Trix[i]
                }
                if inChart.IndMin > inChart.TrixMa[i]{
                    inChart.IndMin = inChart.TrixMa[i]
                }
            } else if inChart.ShowIndicator == "DMA" {
                if inChart.IndMax < inChart.Dma1[i] {
                    inChart.IndMax = inChart.Dma1[i]
                }
                if inChart.IndMax < inChart.Dma2[i] {
                    inChart.IndMax = inChart.Dma2[i]
                }
                if inChart.IndMin > inChart.Dma1[i] {
                    inChart.IndMin = inChart.Dma1[i]
                }
                if inChart.IndMin > inChart.Dma2[i]{
                    inChart.IndMin = inChart.Dma2[i]
                }
            }
        }
    }
    if len(inChart.Shapes) > 0 {
        lastValidIndex := inChart.LastVisibleIndex
        if inChart.LastValidIndex != -1 {
            lastValidIndex = inChart.LastValidIndex
        }
        for s := 0; s <= len(inChart.Shapes); s++ {
            shape := inChart.Shapes[s]
            if len(shape.Datas) > 0{
                for i := inChart.FirstVisibleIndex; i <= lastValidIndex; i++ {
                    if shape.DivIndex == 0 {
                        if !load1 && i == inChart.FirstVisibleIndex {
                            if shape.LeftOrRight {
                                inChart.CandleMax = shape.Datas[i]
                                inChart.CandleMin = shape.Datas[i]
                            } else {
                                inChart.CandleMaxRight = shape.Datas[i]
                                inChart.CandleMinRight = shape.Datas[i]
                            }
                            load1 = true
                        } else {
                            if shape.LeftOrRight {
                                if shape.Datas[i] > inChart.CandleMax {
                                    inChart.CandleMax = shape.Datas[i]
                                }
                                if shape.Datas[i] < inChart.CandleMin {
                                    inChart.CandleMin = shape.Datas[i]
                                }
                            } else {
                                if shape.Datas[i] > inChart.CandleMaxRight {
                                    inChart.CandleMaxRight = shape.Datas[i]
                                }
                                if shape.Datas[i] < inChart.CandleMinRight {
                                    inChart.CandleMinRight = shape.Datas[i]
                                }
                            }
                        }
                    } else if shape.DivIndex == 1 {
                        if !load2 && i == inChart.FirstVisibleIndex {
                            if shape.LeftOrRight{
                                inChart.VolMax = shape.Datas[i]
                                inChart.VolMin = shape.Datas[i]
                            } else {
                                inChart.VolMaxRight = shape.Datas[i]
                                inChart.VolMinRight = shape.Datas[i]
                            }
                            load2 = true
                        } else {
                            if shape.LeftOrRight {
                                if shape.Datas[i] > inChart.VolMax {
                                    inChart.VolMax = shape.Datas[i]
                                }
                                if shape.Datas[i] < inChart.VolMin {
                                    inChart.VolMin = shape.Datas[i]
                                }
                            } else {
                                if shape.Datas[i] > inChart.VolMaxRight {
                                    inChart.VolMaxRight = shape.Datas[i]
                                }
                                if shape.Datas[i] < inChart.VolMinRight {
                                    inChart.VolMinRight = shape.Datas[i]
                                }
                            }
                        }
                    } else if shape.DivIndex == 2 {
                        if !load3 && i == inChart.FirstVisibleIndex {
                            if shape.LeftOrRight {
                                inChart.IndMax = shape.Datas[i]
                                inChart.IndMin = shape.Datas[i]
                            } else {
                                inChart.IndMaxRight = shape.Datas[i]
                                inChart.IndMinRight = shape.Datas[i]
                            }
                            load3 = true
                        } else {
                            if shape.LeftOrRight {
                                if shape.Datas[i] > inChart.IndMax {
                                    inChart.IndMax = shape.Datas[i]
                                }
                                if shape.Datas[i] < inChart.IndMin {
                                    inChart.IndMin = shape.Datas[i]
                                }
                            } else {
                                if shape.Datas[i] > inChart.IndMaxRight {
                                    inChart.IndMaxRight = shape.Datas[i]
                                }
                                if shape.Datas[i] < inChart.IndMinRight {
                                    inChart.IndMinRight = shape.Datas[i]
                                }
                            }
                        }
                    } else if shape.DivIndex == 3 {
                        if !load4 && i == inChart.FirstVisibleIndex {
                            if shape.LeftOrRight {
                                inChart.IndMax2 = shape.Datas[i]
                                inChart.IndMin2 = shape.Datas[i]
                            } else {
                                inChart.IndMax2Right = shape.Datas[i]
                                inChart.IndMin2Right = shape.Datas[i]
                            }
                            load4 = true
                        } else {
                            if shape.LeftOrRight {
                                if shape.Datas[i] > inChart.IndMax2 {
                                    inChart.IndMax2 = shape.Datas[i]
                                }
                                if shape.Datas[i] < inChart.IndMin2 {
                                    inChart.IndMin2 = shape.Datas[i]
                                }
                            } else {
                                if shape.Datas[i] > inChart.IndMax2Right {
                                    inChart.IndMax2Right = shape.Datas[i]
                                }
                                if shape.Datas[i] < inChart.IndMin2Right {
                                    inChart.IndMin2Right = shape.Datas[i]
                                }
                            }
                        }
                    }
                }
            }
            if len(shape.Datas2) > 0 {
                for i := inChart.FirstVisibleIndex; i <= lastValidIndex; i++ {
                    if shape.DivIndex == 0 {
                        if shape.LeftOrRight {
                            if shape.Datas2[i] > inChart.CandleMax {
                                inChart.CandleMax = shape.Datas2[i]
                            }
                            if shape.Datas2[i] < inChart.CandleMin {
                                inChart.CandleMin = shape.Datas2[i]
                            }
                        } else {
                            if shape.Datas2[i] > inChart.CandleMaxRight {
                                inChart.CandleMaxRight = shape.Datas2[i]
                            }
                            if shape.Datas2[i] < inChart.CandleMinRight{
                                inChart.CandleMinRight = shape.Datas2[i]
                            }
                        }
                    } else if shape.DivIndex == 1 {
                        if shape.LeftOrRight {
                            if shape.Datas2[i] > inChart.VolMax {
                                inChart.VolMax = shape.Datas2[i]
                            }
                            if shape.Datas2[i] < inChart.VolMin {
                                inChart.VolMin = shape.Datas2[i]
                            }
                        } else {
                            if shape.Datas2[i] > inChart.VolMaxRight {
                                inChart.VolMaxRight = shape.Datas2[i]
                            }
                            if shape.Datas2[i] < inChart.VolMinRight {
                                inChart.VolMinRight = shape.Datas2[i]
                            }
                        }
                    } else if shape.DivIndex == 2 {
                        if shape.LeftOrRight {
                            if shape.Datas2[i] > inChart.IndMax {
                                inChart.IndMax = shape.Datas2[i]
                            }
                            if shape.Datas2[i] < inChart.IndMin {
                                inChart.IndMin = shape.Datas2[i]
                            }
                        } else {
                            if shape.Datas2[i] > inChart.IndMaxRight {
                                inChart.IndMaxRight = shape.Datas2[i]
                            }
                            if shape.Datas2[i] < inChart.IndMinRight {
                                inChart.IndMinRight = shape.Datas2[i]
                            }
                        }
                    } else if shape.DivIndex == 3 {
                        if shape.LeftOrRight {
                            if shape.Datas2[i] > inChart.IndMax2 {
                                inChart.IndMax2 = shape.Datas2[i]
                            }
                            if shape.Datas2[i] < inChart.IndMin2 {
                                inChart.IndMin2 = shape.Datas2[i]
                            }
                        } else {
                            if shape.Datas2[i] > inChart.IndMax2Right {
                                inChart.IndMax2Right = shape.Datas2[i]
                            }
                            if shape.Datas2[i] < inChart.IndMin2Right {
                                inChart.IndMin2Right = shape.Datas2[i]
                            }
                        }
                    }
                }
            }
        }
    }
    if isTrend {
        subMax := math.Max(math.Abs(inChart.CandleMax - firstOpen), math.Abs(inChart.CandleMin - firstOpen))
        inChart.CandleMax = firstOpen + subMax
        inChart.CandleMin = firstOpen - subMax
    } else {
        if inChart.CandleMax == 0 && inChart.CandleMin == 0 {
            inChart.CandleMax = 1
            inChart.CandleMin = -1
        }
        if inChart.VolMax == 0 && inChart.VolMin == 0 {
            inChart.VolMax = 1
            inChart.VolMin = -1
        }
        if inChart.IndMax == 0 && inChart.IndMin == 0 {
            inChart.IndMax = 1
            inChart.IndMin = -1
        }
        if inChart.IndMax2 == 0 && inChart.IndMin2 == 0 {
            inChart.IndMax2 = 1
            inChart.IndMin2 = -1
        }
        if inChart.CandleMaxRight == 0 && inChart.CandleMinRight == 0 {
            inChart.CandleMaxRight = 1
            inChart.CandleMinRight = -1
        }
        if inChart.VolMaxRight == 0 && inChart.VolMinRight == 0 {
            inChart.VolMaxRight = 1
            inChart.VolMinRight = -1
        }
        if inChart.IndMaxRight == 0 && inChart.IndMinRight == 0 {
            inChart.IndMaxRight = 1
            inChart.IndMinRight = -1
        }
        if inChart.IndMax2Right == 0 && inChart.IndMin2Right == 0 {
            inChart.IndMax2Right = 1
            inChart.IndMin2Right = -1
        }
    }
}

/*
* 绘制线条
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
* divIndex:图层
* datas:数据
* color:颜色
* selected:是否选中
*/
func DrawChartLines(chart *FCView, paint *FCPaint, clipRect FCRect, divIndex int, datas []float64, color string, selected bool) {
    inChart := chart.GetChart()
    maxVisibleRecord := GetChartMaxVisibleCount(chart, inChart.HScalePixel, GetChartWorkAreaWidth(chart))
    lastValidIndex := inChart.LastVisibleIndex
    if inChart.LastValidIndex != -1 {
        lastValidIndex = inChart.LastValidIndex
    }
    var drawPoints []FCPoint
    for i := inChart.FirstVisibleIndex; i <= lastValidIndex; i++ {
        x := GetChartX(chart, i)
        value := datas[i]
        y := GetChartY(chart, divIndex, value)
        drawPoints = append(drawPoints, CreatePoint(x, y))
        if selected {
            kPInterval := int(maxVisibleRecord / 30)
            if kPInterval < 2 {
                kPInterval = 3
            }
            if i % kPInterval == 0 {
                paint.FillRect(color, x - 3, y - 3, x + 3, y + 3)
            }
        }
    }
    paint.DrawPolyline(color, inChart.LineWidthChart, 0, drawPoints)
}

/*
* 绘制线条到右轴
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
* divIndex:图层
* datas:数据
* color:颜色
* selected:是否选中
*/
func DrawChartLinesInRight(chart *FCView, paint *FCPaint, clipRect FCRect, divIndex int, datas []float64, color string, selected bool) {
    inChart := chart.GetChart()
    maxVisibleRecord := GetChartMaxVisibleCount(chart, inChart.HScalePixel, GetChartWorkAreaWidth(chart))
    lastValidIndex := inChart.LastVisibleIndex
    if inChart.LastValidIndex != -1 {
        lastValidIndex = inChart.LastValidIndex
    }
    var drawPoints []FCPoint
    for i := inChart.FirstVisibleIndex; i <= lastValidIndex; i++ {
        x := GetChartX(chart, i)
        value := datas[i]
        y := GetChartYInRight(chart, divIndex, value)
        drawPoints = append(drawPoints, CreatePoint(x, y))
        if selected {
            kPInterval := int(maxVisibleRecord / 30)
            if kPInterval < 2 {
                kPInterval = 3
            }
            if i % kPInterval == 0 {
                paint.FillRect(color, x - 3, y - 3, x + 3, y + 3)
            }
        }
    }
    paint.DrawPolyline(color, inChart.LineWidthChart, 0, drawPoints)
}

/*
* 绘制画线工具
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawChartPlot(chart *FCView, paint *FCPaint, clipRect FCRect) {
    inChart := chart.GetChart()
    if len(inChart.Plots) > 0{
        divHeight := GetCandleDivHeight(chart)
        paint.SetClip(inChart.LeftVScaleWidth, 20, chart.Size.Cx - inChart.RightVScaleWidth, divHeight)
        for i := 0; i < len(inChart.Plots); i++ {
            plot := inChart.Plots[i]
            index1 := 0
            index2 := 0
            index3 := 0
            mpx1 := 0.0
            mpy1 := 0.0
            mpx2 := 0.0
            mpy2 := 0.0
            mpx3 := 0.0
            mpy3 := 0.0
            if plot.PlotType == "LRLine" || plot.PlotType == "LRChannel" || plot.PlotType == "LRBand" {
                var list []float64
                index1 = GetChartIndexByDate(chart, plot.Key1)
                index2 = GetChartIndexByDate(chart, plot.Key2)
                minIndex := int(math.Min(float64(index1), float64(index2)))
                maxIndex := int(math.Max(float64(index1), float64(index2)))
                for j := minIndex; j <= maxIndex; j++ {
                    list = append(list, inChart.Data[j].Close)
                }
                LinearRegressionEquation(chart, list)
                plot.Value1 = inChart.BChart
                plot.Value2 = inChart.KChart * float64(maxIndex - minIndex + 1) + inChart.BChart
            }else if plot.PlotType == "BoxLine" || plot.PlotType == "TironeLevels" || plot.PlotType == "QuadrantLines" {
                GetCandleRange(chart, plot)
                nHigh := inChart.NHighChart
                nLow := inChart.NLowChart
                index1 := GetChartIndexByDate(chart, plot.Key1)
                index2 := GetChartIndexByDate(chart, plot.Key2)
                plot.Key1 = GetChartDateByIndex(chart, int(math.Min(float64(index1), float64(index2))))
                plot.Key2 = GetChartDateByIndex(chart, int(math.Max(float64(index1), float64(index2))))
                plot.Value1 = nHigh
                plot.Value2 = nLow
            }
            if plot.Key1 > 0 {
                index1 = GetChartIndexByDate(chart, plot.Key1)
                mpx1 = GetChartX(chart, index1)
                mpy1 = GetChartY(chart, 0, plot.Value1)
                if inChart.GetSelectedPlot() == plot {
                    paint.FillEllipse(plot.PointColor, mpx1 - inChart.PlotPointSizeChart, mpy1 - inChart.PlotPointSizeChart, mpx1 + inChart.PlotPointSizeChart, mpy1 + inChart.PlotPointSizeChart)
                }
            }
            if plot.Key2 > 0 {
                index2 = GetChartIndexByDate(chart, plot.Key2)
                mpx2 = GetChartX(chart, index2)
                mpy2 = GetChartY(chart, 0, plot.Value2)
                if inChart.GetSelectedPlot() == plot {
                    paint.FillEllipse(plot.PointColor, mpx2 - inChart.PlotPointSizeChart, mpy2 - inChart.PlotPointSizeChart, mpx2 + inChart.PlotPointSizeChart, mpy2 + inChart.PlotPointSizeChart)
                }
            }
            if plot.Key3 > 0 {
                index3 = GetChartIndexByDate(chart, plot.Key3)
                mpx3 = GetChartX(chart, index3)
                mpy3 = GetChartY(chart, 0, plot.Value3)
                if inChart.GetSelectedPlot() == plot {
                    paint.FillEllipse(plot.PointColor, mpx3 - inChart.PlotPointSizeChart, mpy3 - inChart.PlotPointSizeChart, mpx3 + inChart.PlotPointSizeChart, mpy3 + inChart.PlotPointSizeChart)
                }
            }
            if plot.PlotType == "Line" {
                LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                if mpx2 == mpx1 {
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, 0, mpx1, divHeight)
                } else {
                    newX1 := inChart.LeftVScaleWidth
                    newY1 := newX1 * inChart.KChart + inChart.BChart
                    newX2 := chart.Size.Cx - inChart.RightVScaleWidth
                    newY2 := newX2 * inChart.KChart + inChart.BChart
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, newX1, newY1, newX2, newY2)
                }
            }else if plot.PlotType == "AngleLine" {
                LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                if mpx2 == mpx1 {
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, 0, mpx1, divHeight)
                } else {
                    newX1 := inChart.LeftVScaleWidth
                    newY1 := newX1 * inChart.KChart + inChart.BChart
                    newX2 := chart.Size.Cx - inChart.RightVScaleWidth
                    newY2 := newX2 * inChart.KChart + inChart.BChart
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, newX1, newY1, newX2, newY2)
                }
                LineXY(chart, mpx1, mpy1, mpx3, mpy3, 0, 0)
                if mpx3 == mpx1 {
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, 0, mpx1, divHeight)
                } else {
                    newX1 := inChart.LeftVScaleWidth
                    newY1 := newX1 * inChart.KChart + inChart.BChart
                    newX2 := chart.Size.Cx - inChart.RightVScaleWidth
                    newY2 := newX2 * inChart.KChart + inChart.BChart
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, newX1, newY1, newX2, newY2)
                }
            }else if plot.PlotType == "Parallel" {
                LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                if mpx2 == mpx1 {
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, 0, mpx1, divHeight)
                } else {
                    newX1 := inChart.LeftVScaleWidth
                    newY1 := newX1 * inChart.KChart + inChart.BChart
                    newX2 := chart.Size.Cx - inChart.RightVScaleWidth
                    newY2 := newX2 * inChart.KChart + inChart.BChart
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, newX1, newY1, newX2, newY2)
                }
                newB := mpy3 - inChart.KChart * mpx3
                if mpx2 == mpx1 {
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx3, 0, mpx3, divHeight)
                } else {
                    newX1 := inChart.LeftVScaleWidth
                    newY1 := newX1 * inChart.KChart + newB
                    newX2 := chart.Size.Cx - inChart.RightVScaleWidth
                    newY2 := newX2 * inChart.KChart + newB
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, newX1, newY1, newX2, newY2)
                }
            }else if plot.PlotType == "Percent" {
                list := GetPercentParams(mpy1, mpy2)
                var texts []string
                texts = append(texts, "0%")
                texts = append(texts, "25%")
                texts = append(texts, "50%")
                texts = append(texts, "75%")
                texts = append(texts, "100%")
                for j := 0; j < len(list); j++ {
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, inChart.LeftVScaleWidth, list[j], chart.Size.Cx - inChart.RightVScaleWidth, list[j])
                    tSize := paint.TextSize(texts[j], chart.Font)
                    paint.DrawText(texts[j], chart.TextColor, chart.Font, inChart.LeftVScaleWidth + 5, list[j] - tSize.Cy - 2)
                }
            }else if plot.PlotType == "FiboTimezone" {
                fValue := 1
                aIndex := index1
                pos := 1
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, 0, mpx1, divHeight)
                tSize := paint.TextSize("1", chart.Font)
                paint.DrawText("1", chart.TextColor, chart.Font, mpx1, divHeight - tSize.Cy)
                for{
                    if aIndex + fValue <= inChart.LastVisibleIndex{
                        fValue = FibonacciValue(pos)
                        newIndex := aIndex + fValue
                        newX := GetChartX(chart, newIndex)
                        paint.DrawLine(plot.LineColor, plot.LineWidth, 0, newX, 0, newX, divHeight)
                        tSize2 := paint.TextSize(ConvertIntToStr(fValue), chart.Font)
                        paint.DrawText(ConvertIntToStr(fValue), chart.TextColor, chart.Font, newX, divHeight - tSize2.Cy)
                        pos += 1
                    }else{
                        break
                    }
                }
            }else if plot.PlotType == "SpeedResist" {
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx2, mpy2)
                if mpx1 != mpx2 && mpy1 != mpy2 {
                    firstP := CreatePoint(mpx2, mpy2 - (mpy2 - mpy1) / 3)
                    secondP := CreatePoint(mpx2, mpy2 - (mpy2 - mpy1) * 2 / 3)
                    startP := CreatePoint(mpx1, mpy1)
                    fK := 0.0
                    fB := 0.0
                    sK := 0.0
                    sB := 0.0
                    LineXY(chart, startP.X, startP.Y, firstP.X, firstP.Y, 0, 0)
                    fK = inChart.KChart
                    fB = inChart.BChart
                    LineXY(chart, startP.X, startP.Y, secondP.X, secondP.Y, 0, 0)
                    sK = inChart.KChart
                    sB = inChart.BChart
                    newYF := 0.0
                    newYS := 0.0
                    newX := 0.0
                    if mpx2 > mpx1 {
                        newYF = fK * (chart.Size.Cx - inChart.RightVScaleWidth) + fB
                        newYS = sK * (chart.Size.Cx - inChart.RightVScaleWidth) + sB
                        newX = (chart.Size.Cx - inChart.RightVScaleWidth)
                    }else {
                        newYF = fB
                        newYS = sB
                        newX = inChart.LeftVScaleWidth
                    }
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, startP.X, startP.Y, newX, newYF)
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, startP.X, startP.Y, newX, newYS)
                }
            }else if plot.PlotType == "FiboFanline" {
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx2, mpy2)
                if mpx1 != mpx2 && mpy1 != mpy2 {
                    firstP := CreatePoint(mpx2, mpy2 - (mpy2 - mpy1) * 0.382)
                    secondP := CreatePoint(mpx2, mpy2 - (mpy2 - mpy1) * 0.5)
                    thirdP := CreatePoint(mpx2, mpy2 - (mpy2 - mpy1) * 0.618)
                    startP := CreatePoint(mpx1, mpy1)
                    var listP []FCPoint
                    listP = append(listP, firstP)
                    listP = append(listP, secondP)
                    listP = append(listP, thirdP)
                    listSize := len(listP)
                    for j := 0; j < listSize; j++ {
                        //获取直线参数
                        LineXY(chart, startP.X, startP.Y, listP[j].X, listP[j].Y, 0, 0)
                        newX := 0.0
                        newY := 0.0
                        if mpx2 > mpx1 {
                            newY = inChart.KChart * (chart.Size.Cx - inChart.RightVScaleWidth) + inChart.BChart
                            newX = (chart.Size.Cx - inChart.RightVScaleWidth)
                        }else {
                            newY = inChart.BChart
                            newX = inChart.LeftVScaleWidth
                        }
                        paint.DrawLine(plot.LineColor, plot.LineWidth, 0, startP.X, startP.Y, newX, newY)
                    }
                }
            }else if plot.PlotType == "LRLine"{
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx2, mpy2)
            }else if plot.PlotType == "LRBand" {
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx2, mpy2)
                GetLRBandRange(chart, plot, inChart.KChart, inChart.BChart)
                mpy1 = GetChartY(chart, 0, plot.Value1 + inChart.UpSubValue)
                mpy2 = GetChartY(chart, 0, plot.Value2 + inChart.UpSubValue)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx2, mpy2)
                mpy1 = GetChartY(chart, 0, plot.Value1 - inChart.DownSubValue)
                mpy2 = GetChartY(chart, 0, plot.Value2 - inChart.DownSubValue)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx2, mpy2)
            }else if plot.PlotType == "LRChannel" {
                GetLRBandRange(chart, plot, inChart.KChart, inChart.BChart)
                LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                rightX := chart.Size.Cx - inChart.RightVScaleWidth
                rightY := rightX * inChart.KChart + inChart.BChart
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, rightX, rightY)
                mpy1 = GetChartY(chart, 0, plot.Value1 + inChart.UpSubValue)
                mpy2 = GetChartY(chart, 0, plot.Value2 + inChart.UpSubValue)
                LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                rightY = rightX * inChart.KChart + inChart.BChart
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, rightX, rightY)
                mpy1 = GetChartY(chart, 0, plot.Value1 - inChart.DownSubValue)
                mpy2 = GetChartY(chart, 0, plot.Value2 - inChart.DownSubValue)
                LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                rightY = rightX * inChart.KChart + inChart.BChart
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, rightX, rightY)
            }else if plot.PlotType == "Segment" {
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx2, mpy2)
            } else if plot.PlotType == "Ray" {
                LineXY(chart, mpx1, mpy1, mpx2, mpy2, 0, 0)
                if inChart.KChart != 0 || inChart.BChart != 0 {
                    leftX := inChart.LeftVScaleWidth
                    leftY := leftX * inChart.KChart + inChart.BChart
                    rightX := chart.Size.Cx - inChart.RightVScaleWidth
                    rightY := rightX * inChart.KChart + inChart.BChart
                    if mpx1 >= mpx2 {
                        paint.DrawLine(plot.LineColor, plot.LineWidth, 0, leftX, leftY, mpx1, mpy1)
                    } else {
                        paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, rightX, rightY)
                    }
                }else {
                    if mpy1 >= mpy2 {
                        paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx1, 0)
                    } else {
                        paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx1, divHeight)
                    }
                }
            }else if plot.PlotType == "Triangle" {
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx2, mpy2)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx2, mpy2, mpx3, mpy3)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx3, mpy3)
            }else if plot.PlotType == "SymmetricTriangle" {
                if mpx2 != mpx1 {
                    a := (mpy2 - mpy1) / (mpx2 - mpx1)
                    b := mpy1 - a * mpx1
                    c := -a
                    d := mpy3 - c * mpx3
                    leftX := inChart.LeftVScaleWidth
                    leftY := leftX * a + b
                    rightX := chart.Size.Cx - inChart.RightVScaleWidth
                    rightY := rightX * a + b
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, leftX, leftY, rightX, rightY)
                    leftY = leftX * c + d
                    rightY = rightX * c + d
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, leftX, leftY, rightX, rightY)
                } else {
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, 0, mpx1, divHeight)
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx3, 0, mpx3, divHeight)
                }
            }else if plot.PlotType == "Rect" {
                sX1 := math.Min(mpx1, mpx2)
                sY1 := math.Min(mpy1, mpy2)
                sX2 := math.Max(mpx1, mpx2)
                sY2 := math.Max(mpy1, mpy2)
                paint.DrawRect(plot.LineColor, plot.LineWidth, 0, sX1, sY1, sX2, sY2)
            } else if plot.PlotType == "Cycle" {
                r := math.Sqrt(math.Abs((mpx2 - mpx1) * (mpx2 - mpx1) + (mpy2 - mpy1) * (mpy2 - mpy1)))
                paint.DrawEllipse(plot.LineColor, plot.LineWidth, 0, mpx1 - r, mpy1 - r, mpx1 + r, mpy1 + r)
            } else if plot.PlotType == "CircumCycle" {
                EllipseOR(chart, mpx1, mpy1, mpx2, mpy2, mpx3, mpy3)
                paint.DrawEllipse(plot.LineColor, plot.LineWidth, 0, inChart.OXChart - inChart.RChart, inChart.OYChart - inChart.RChart, inChart.OXChart + inChart.RChart, inChart.OYChart + inChart.RChart)
            }else if plot.PlotType == "Ellipse" {
                x1 := 0.0
                y1 := 0.0
                x2 := 0.0
                y2 := 0.0
                if mpx1 <= mpx2 {
                    x1 = mpx2
                    y1 = mpy2
                    x2 = mpx1
                    y2 = mpy1
                } else {
                    x1 = mpx1
                    y1 = mpy1
                    x2 = mpx2
                    y2 = mpy2
                }
                x := x1 - (x1 - x2)
                y := 0.0
                width := (x1 - x2) * 2
                height := 0.0
                if y1 >= y2 {
                    height = (y1 - y2) * 2
                }else {
                    height = (y2 - y1) * 2
                }
                y = y2 - height / 2
                paint.DrawEllipse(plot.LineColor, plot.LineWidth, 0, x, y, x + width, y + height)
            }else if plot.PlotType == "ParalleGram" {
                Parallelogram(chart, mpx1, mpy1, mpx2, mpy2, mpx3, mpy3)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx1, mpy1, mpx2, mpy2)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx2, mpy2, mpx3, mpy3)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, mpx3, mpy3, inChart.X4Chart, inChart.Y4Chart)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, inChart.X4Chart, inChart.Y4Chart, mpx1, mpy1)
            }else if plot.PlotType == "BoxLine" {
                sX1 := math.Min(mpx1, mpx2)
                sY1 := math.Min(mpy1, mpy2)
                sX2 := math.Max(mpx1, mpx2)
                sY2 := math.Max(mpy1, mpy2)
                paint.DrawRect(plot.LineColor, plot.LineWidth, 0, sX1, sY1, sX2, sY2)
                paint.DrawText(ConvertIntToStr(int(math.Abs(float64(index2 - index1)) + 1)), chart.TextColor, chart.Font, sX1 + 2, sY1 + 2)
                var closeList []float64
                for j := index1; j <= index2; j++ {
                    closeList = append(closeList, inChart.Data[j].Close)
                }
                avgClose := AvgValue(closeList)
                closeY := GetChartY(chart, 0, avgClose)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, sX1, closeY, sX2, closeY)
                drawAvg := ToFixed(avgClose, inChart.CandleDigit)
                tSize := paint.TextSize(drawAvg, chart.Font)
                paint.DrawText(drawAvg, chart.TextColor, chart.Font, sX1 + 2, closeY - tSize.Cy - 2)
            }else if plot.PlotType == "TironeLevels" {
                sX1 := math.Min(mpx1, mpx2)
                sY1 := math.Min(mpy1, mpy2)
                sX2 := math.Max(mpx1, mpx2)
                sY2 := math.Max(mpy1, mpy2)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, sX1, sY1, sX2, sY1)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, sX1, sY2, sX2, sY2)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, sX1 + (sX2 - sX1) / 2, sY1, sX1 + (sX2 - sX1) / 2, sY2)
                t2 := inChart.NHighChart - (inChart.NHighChart - inChart.NLowChart) / 3
                t3 := inChart.NHighChart - (inChart.NHighChart - inChart.NLowChart) / 2
                t4 := inChart.NHighChart - 2 * (inChart.NHighChart - inChart.NLowChart) / 3
                var tList []float64
                tList = append(tList, t2)
                tList = append(tList, t3)
                tList = append(tList, t4)
                for j := 0; j < len(tList); j++ {
                    y := GetChartY(chart, 0, tList[j])
                    //画直线
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, inChart.LeftVScaleWidth, y, chart.Size.Cx - inChart.RightVScaleWidth, y)
                    str := ToFixed(tList[j], inChart.CandleDigit)
                    tSize := paint.TextSize(str, chart.Font)
                    paint.DrawText(str, chart.TextColor, chart.Font, inChart.LeftVScaleWidth + 2, y - tSize.Cy - 2)
                }
            }else if plot.PlotType == "QuadrantLines" {
                sX1 := math.Min(mpx1, mpx2)
                sY1 := math.Min(mpy1, mpy2)
                sX2 := math.Max(mpx1, mpx2)
                sY2 := math.Max(mpy1, mpy2)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, sX1, sY1, sX2, sY1)
                paint.DrawLine(plot.LineColor, plot.LineWidth, 0, sX1, sY2, sX2, sY2)
                t2 := inChart.NHighChart - (inChart.NHighChart - inChart.NLowChart) / 4
                t3 := inChart.NHighChart - (inChart.NHighChart - inChart.NLowChart) / 2
                t4 := inChart.NHighChart - 3 * (inChart.NHighChart - inChart.NLowChart) / 4
                var tList []float64
                tList = append(tList, t2)
                tList = append(tList, t3)
                tList = append(tList, t4)
                for j := 0; j < len(tList); j++ {
                    y := GetChartY(chart, 0, tList[j])
                    //画直线
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, sX1, y, sX2, y)
                }
            }else if plot.PlotType == "GoldenRatio" {
                sY1 := math.Min(mpy1, mpy2)
                sY2 := math.Max(mpy1, mpy2)
                var ranges []float64
                ranges = append(ranges, 0)
                ranges = append(ranges, 0.236)
                ranges = append(ranges, 0.382)
                ranges = append(ranges, 0.5)
                ranges = append(ranges, 0.618)
                ranges = append(ranges, 0.809)
                ranges = append(ranges, 1)
                ranges = append(ranges, 1.382)
                ranges = append(ranges, 1.618)
                ranges = append(ranges, 2)
                ranges = append(ranges, 2.382)
                ranges = append(ranges, 2.618)
                for j := 0; j < len(ranges); j++ {
                    newY := 0.0
                    if sY1 <= sY2{
                        newY = sY1 + (sY2 - sY1) * ranges[j]
                    }else{
                        newY = sY2 + (sY1 - sY2) * (1 - ranges[j])
                    }
                    paint.DrawLine(plot.LineColor, plot.LineWidth, 0, inChart.LeftVScaleWidth, newY, chart.Size.Cx - inChart.RightVScaleWidth, newY)
                    newPoint := CreatePoint(0, newY)
                    value := GetCandleDivValue(chart, newPoint)
                    str := ToFixed(value, inChart.CandleDigit)
                    tSize := paint.TextSize(str, chart.Font)
                    paint.DrawText(str, chart.TextColor, chart.Font, inChart.LeftVScaleWidth + 2, newY - tSize.Cy - 2)
                }
            }else if plot.PlotType == "ArrowSegment" {
                arrowSize := 24.0
                slopy := 0.0
                cosy := 0.0
                siny := 0.0
                slopy = math.Atan2(mpy1 - mpy2, mpx1 - mpx2)
                cosy = math.Cos(slopy)
                siny = math.Sin(slopy)
                ptPoint := CreatePoint(0, 0)
                ptPoint.X = mpx2
                ptPoint.Y = mpy2
                var pts []FCPoint
                pts = append(pts, CreatePoint(ptPoint.X, ptPoint.Y))
                pts = append(pts, CreatePoint(ptPoint.X + (arrowSize * cosy - (arrowSize / 2.0 * siny) + 0.5), ptPoint.Y + (arrowSize * siny + (arrowSize / 2.0 * cosy) + 0.5)))
                pts = append(pts, CreatePoint(ptPoint.X + (arrowSize * cosy + arrowSize / 2.0 * siny + 0.5), ptPoint.Y - (arrowSize / 2.0 * cosy - arrowSize * siny + 0.5)))
                arrowSize = 20.0
                ptPoint2 := CreatePoint(0, 0)
                ptPoint2.X = mpx2
                ptPoint2.Y = mpy2
                var pts2 []FCPoint
                pts2 = append(pts2, CreatePoint(ptPoint2.X, ptPoint2.Y))
                pts2 = append(pts2, CreatePoint(ptPoint2.X + (arrowSize * cosy - (arrowSize / 2.0 * siny) + 0.5), ptPoint2.Y + (arrowSize * siny + (arrowSize / 2.0 * cosy) + 0.5)))
                pts2 = append(pts2, CreatePoint(ptPoint2.X + (arrowSize * cosy + arrowSize / 2.0 * siny + 0.5), ptPoint2.Y - (arrowSize / 2.0 * cosy - arrowSize * siny + 0.5)))
                LineXY(chart, pts2[1].X, pts2[1].Y, pts2[2].X, pts2[2].Y, 0, 0)
                newX1 := 0.0
                newY1 := 0.0
                newX2 := 0.0
                newY2 := 0.0
                if pts2[1].X > pts2[2].X {
                    newX1 = pts2[2].X + (pts2[1].X - pts2[2].X) / 3
                    newX2 = pts2[2].X + (pts2[1].X - pts2[2].X) * 2 / 3
                } else {
                    newX1 = pts2[1].X + (pts2[2].X - pts2[1].X) / 3
                    newX2 = pts2[1].X + (pts2[2].X - pts2[1].X) * 2 / 3
                }
                if inChart.KChart == 0 && inChart.BChart == 0 {
                    if pts2[1].Y > pts2[2].Y {
                        newY1 = pts2[2].Y + (pts2[1].Y - pts2[2].Y) / 3
                        newY2 = pts2[2].Y + (pts2[1].Y - pts2[2].Y) * 2 / 3
                    } else {
                        newY1 = pts2[1].Y + (pts2[2].Y - pts2[1].Y) / 3
                        newY2 = pts2[1].Y + (pts2[2].Y - pts2[1].Y) * 2 / 3
                    }
                } else {
                    newY1 = (inChart.KChart * newX1) + inChart.BChart
                    newY2 = (inChart.KChart * newX2) + inChart.BChart
                }
                p2 := CreatePoint(newX1, newY1)
                pts2[1] = p2
                p3 := CreatePoint(newX2, newY2)
                pts2[2] = p3
                var drawPoints []FCPoint
                drawPoints = append(drawPoints, CreatePoint(ptPoint.X, ptPoint.Y))
                drawPoints = append(drawPoints, CreatePoint(pts[1].X, pts[1].Y))
                if mpy1 >= mpy2 {
                    drawPoints = append(drawPoints, CreatePoint(pts2[1].X, pts2[1].Y))
                } else {
                    drawPoints = append(drawPoints, CreatePoint(pts2[2].X, pts2[2].Y))
                }
                drawPoints = append(drawPoints, CreatePoint(mpx1, mpy1))
                if mpy1 >= mpy2 {
                    drawPoints = append(drawPoints, CreatePoint(pts2[2].X, pts2[2].Y))
                } else {
                    drawPoints = append(drawPoints, CreatePoint(pts2[1].X, pts2[1].Y))
                }
                drawPoints = append(drawPoints, CreatePoint(pts[2].X, pts[2].Y))
                paint.FillPolygon(plot.LineColor, drawPoints)
            }
        }
        paint.SetClip(clipRect.Left, clipRect.Top, clipRect.Right, clipRect.Bottom)
    }
}

/*
* 绘制图表
* chart:图表
* paint:绘图对象
* clipRect:裁剪区域
*/
func DrawChartStock(chart *FCView, paint *FCPaint, clipRect FCRect) {
    inChart := chart.GetChart()
    candleHeight := GetCandleDivHeight(chart)
    volHeight := GetVolDivHeight(chart)
    indHeight := GetIndDivHeight(chart)
    isTrend := false
    if inChart.Cycle == "trend"{
        isTrend = true
    }
    cWidth := float64(int((inChart.HScalePixel - 3) / 2))
    if cWidth < 0 {
        cWidth = 0
    }
    lastValidIndex := inChart.LastVisibleIndex
    if inChart.LastValidIndex != -1 {
        lastValidIndex = inChart.LastValidIndex
    }
    if len(inChart.Data) > 0 {
        maxVisibleRecord := GetChartMaxVisibleCount(chart, inChart.HScalePixel, GetChartWorkAreaWidth(chart))
        if isTrend {
            var drawPoints []FCPoint
            for i := inChart.FirstVisibleIndex; i <= lastValidIndex; i++ {
                x := GetChartX(chart, i)
                close := inChart.Data[i].Close
                closeY := GetChartY(chart, 0, close)
                drawPoints = append(drawPoints, CreatePoint(x, closeY))
            }
            paint.DrawPolyline(inChart.IndicatorColors[7], inChart.LineWidthChart, 0, drawPoints)
        }
        hasMinTag := false
        hasMaxTag := false
        for i := inChart.FirstVisibleIndex; i <= lastValidIndex; i++ {
            x := GetChartX(chart, i)
            open := inChart.Data[i].Open
            close := inChart.Data[i].Close
            high := inChart.Data[i].High
            low := inChart.Data[i].Low
            openY := GetChartY(chart, 0, open)
            closeY := GetChartY(chart, 0, close)
            highY := GetChartY(chart, 0, high)
            lowY := GetChartY(chart, 0, low)
            if close >= open {
                if !isTrend {
                    paint.DrawLine(inChart.UpColor, inChart.LineWidthChart, 0, x, highY, x, lowY)
                    if cWidth > 0 {
                        if close == open {
                            paint.DrawLine(inChart.UpColor, inChart.LineWidthChart, 0, x - cWidth, closeY, x + cWidth, closeY)
                        }else {
                            paint.FillRect(inChart.UpColor, x - cWidth, closeY, x + cWidth, openY)
                        }
                    }
                } 
            } else {
                if !isTrend {
                    paint.DrawLine(inChart.DownColor, inChart.LineWidthChart, 0, x, highY, x, lowY)
                    if cWidth > 0 {
                        paint.FillRect(inChart.DownColor, x - cWidth, openY, x + cWidth, closeY)
                    }
                }
            }
            if inChart.SelectShape == "CANDLE" {
                kPInterval := int(maxVisibleRecord / 30)
                if kPInterval < 2 {
                    kPInterval = 3
                }
                if i % kPInterval == 0 {
                    if !isTrend {
                        paint.FillRect(inChart.IndicatorColors[0], x - 3, closeY - 3, x + 3, closeY + 3)
                    } 
                }
            }
            if !isTrend {
                if !hasMaxTag {
                    if high == inChart.CandleMax {
                        tag := ToFixed(high, inChart.CandleDigit)
                        tSize := paint.TextSize(tag, chart.Font)
                        paint.DrawText(tag, chart.TextColor, chart.Font, x - tSize.Cx / 2, highY - tSize.Cy / 2 - 2)
                        hasMaxTag = true
                    }
                }
                if !hasMinTag {
                    if low == inChart.CandleMin {
                        tag := ToFixed(low, inChart.CandleDigit)
                        tSize := paint.TextSize(tag, chart.Font)
                        paint.DrawText(tag, chart.TextColor, chart.Font, x - tSize.Cx / 2, lowY + 2 + tSize.Cy / 2)
                        hasMinTag = true
                    }
                }
            }
        }
        for i := inChart.FirstVisibleIndex; i <= lastValidIndex; i++ {
            x := GetChartX(chart, i)
            open := inChart.Data[i].Open
            close := inChart.Data[i].Close
            volY := 0.0
            zeroY := 0.0
            if volHeight > 0 {
                volume := inChart.Data[i].Volume
                volY = GetChartY(chart, 1, volume)
                zeroY = GetChartY(chart, 1, 0)
            }
            if close >= open {
                if isTrend {
                    if volHeight > 0 {
                        paint.DrawLine(inChart.IndicatorColors[6], inChart.LineWidthChart, 0, x, volY, x, zeroY)
                    }
                } else {
                    if cWidth > 0 {
                        if volHeight > 0 {
                            paint.FillRect(inChart.UpColor, x - cWidth, volY, x + cWidth, zeroY)
                        }
                    } else {
                        if volHeight > 0 {
                            paint.DrawLine(inChart.UpColor, inChart.LineWidthChart, 0, x - cWidth, volY, x + cWidth, zeroY)
                        }
                    }
                }
            } else {
                if isTrend {
                    if volHeight > 0 {
                        paint.DrawLine(inChart.IndicatorColors[6], inChart.LineWidthChart, 0, x, volY, x, zeroY)
                    }
                } else {
                    if cWidth > 0 {
                        if volHeight > 0 {
                            paint.FillRect(inChart.DownColor, x - cWidth, volY, x + cWidth, zeroY)
                        }
                    } else {
                        if volHeight > 0 {
                            paint.DrawLine(inChart.DownColor, inChart.LineWidthChart, 0, x - cWidth, volY, x + cWidth, zeroY)
                        }
                    }
                }
            }
            if inChart.SelectShape == "VOL" {
                kPInterval := int(maxVisibleRecord / 30)
                if kPInterval < 2 {
                    kPInterval = 3
                }
                if i % kPInterval == 0 {
                    paint.FillRect(inChart.IndicatorColors[0], x - 3, volY - 3, x + 3, volY + 3)
                }
            }
        }
        if !isTrend{
            paint.SetClip(inChart.LeftVScaleWidth, 20, chart.Size.Cx - inChart.RightVScaleWidth, candleHeight)
            if inChart.MainIndicator == "BOLL" {
                if inChart.SelectShape == inChart.MainIndicator && inChart.SelectShapeEx == "MID"{
					DrawChartLines(chart, paint, clipRect, 0, inChart.BollMid, inChart.IndicatorColors[0], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 0, inChart.BollMid, inChart.IndicatorColors[0], false)
                }
				if inChart.SelectShape == inChart.MainIndicator && inChart.SelectShapeEx == "UP"{
					DrawChartLines(chart, paint, clipRect, 0, inChart.BollUp, inChart.IndicatorColors[1], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 0, inChart.BollUp, inChart.IndicatorColors[1], false)
                }
				if inChart.SelectShape == inChart.MainIndicator && inChart.SelectShapeEx == "DOWN"{
					DrawChartLines(chart, paint, clipRect, 0, inChart.BollDown, inChart.IndicatorColors[2], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 0, inChart.BollDown, inChart.IndicatorColors[2], false)
                }
            } else if inChart.MainIndicator == "MA" {
                if inChart.SelectShape == inChart.MainIndicator && inChart.SelectShapeEx == "5"{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma5, inChart.IndicatorColors[0], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma5, inChart.IndicatorColors[0], false)
                }
				if inChart.SelectShape == inChart.MainIndicator && inChart.SelectShapeEx == "10"{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma10, inChart.IndicatorColors[1], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma10, inChart.IndicatorColors[1], false)
                }
				if inChart.SelectShape == inChart.MainIndicator && inChart.SelectShapeEx == "20"{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma20, inChart.IndicatorColors[2], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma20, inChart.IndicatorColors[2], false)
                }
				if inChart.SelectShape == inChart.MainIndicator && inChart.SelectShapeEx == "30"{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma30, inChart.IndicatorColors[3], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma30, inChart.IndicatorColors[3], false)
                }
				if inChart.SelectShape == inChart.MainIndicator && inChart.SelectShapeEx == "120"{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma120, inChart.IndicatorColors[4], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma120, inChart.IndicatorColors[4], false)
                }
				if inChart.SelectShape == inChart.MainIndicator && inChart.SelectShapeEx == "250"{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma250, inChart.IndicatorColors[5], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 0, inChart.Ma250, inChart.IndicatorColors[5], false)
                }
            }
            paint.SetClip(clipRect.Left, clipRect.Top, clipRect.Right, clipRect.Bottom)
        }
        if indHeight > 0 {
            if inChart.ShowIndicator == "MACD" {
                zeroY := GetChartY(chart, 2, 0)
                paint.DrawLine(inChart.IndicatorColors[4], inChart.LineWidthChart, 0, inChart.LeftVScaleWidth, zeroY, GetChartX(chart, inChart.LastVisibleIndex), zeroY)
                for i := inChart.FirstVisibleIndex; i <= lastValidIndex; i++ {
                    x := GetChartX(chart, i)
                    macd := inChart.Allmacdarr[i]
                    macdY := GetChartY(chart, 2, macd)
                    if macdY < zeroY {
                        paint.DrawLine(inChart.IndicatorColors[3], inChart.LineWidthChart, 0, x, macdY, x, zeroY)
                    } else {
                        paint.DrawLine(inChart.IndicatorColors[4], inChart.LineWidthChart, 0, x, macdY, x, zeroY)
                    }
                    if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "MACD" {
                        kPInterval := int(maxVisibleRecord / 30)
                        if kPInterval < 2 {
                            kPInterval = 3
                        }
                        if i % kPInterval == 0 {
                            paint.FillRect(inChart.IndicatorColors[4], x - 3, macdY - 3, x + 3, macdY + 3)
                        }
                    }
                }
                if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "DIF"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Alldifarr, inChart.IndicatorColors[0], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Alldifarr, inChart.IndicatorColors[0], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "DEA"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Alldeaarr, inChart.IndicatorColors[1], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Alldeaarr, inChart.IndicatorColors[1], false)
                }
            } else if inChart.ShowIndicator == "KDJ"{
                if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "K"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.KdjK, inChart.IndicatorColors[0], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.KdjK, inChart.IndicatorColors[0], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "D"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.KdjD, inChart.IndicatorColors[1], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.KdjD, inChart.IndicatorColors[1], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "J"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.KdjJ, inChart.IndicatorColors[2], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.KdjJ, inChart.IndicatorColors[2], false)
                }
            } else if inChart.ShowIndicator == "RSI" {
                if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "6"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Rsi1, inChart.IndicatorColors[5], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Rsi1, inChart.IndicatorColors[5], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "12"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Rsi2, inChart.IndicatorColors[1], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Rsi2, inChart.IndicatorColors[1], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "24"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Rsi3, inChart.IndicatorColors[2], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Rsi3, inChart.IndicatorColors[2], false)
                }
            }else if inChart.ShowIndicator == "BIAS" {
                if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "1"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Bias1, inChart.IndicatorColors[5], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Bias1, inChart.IndicatorColors[5], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "2"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Bias2, inChart.IndicatorColors[1], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Bias2, inChart.IndicatorColors[1], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "3"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Bias3, inChart.IndicatorColors[2], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Bias3, inChart.IndicatorColors[2], false)
                }
            }else if inChart.ShowIndicator == "ROC" {
                if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "ROC"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Roc, inChart.IndicatorColors[0], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Roc, inChart.IndicatorColors[0], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "ROCMA"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.RocMa, inChart.IndicatorColors[1], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.RocMa, inChart.IndicatorColors[1], false)
                }
            } else if inChart.ShowIndicator == "WR" {
                if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "1"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Wr1, inChart.IndicatorColors[0], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Wr1, inChart.IndicatorColors[0], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "2"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Wr2, inChart.IndicatorColors[1], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Wr2, inChart.IndicatorColors[1], false)
                }   
            } else if inChart.ShowIndicator == "CCI" {
                if inChart.SelectShape == inChart.ShowIndicator{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Cci, inChart.IndicatorColors[0], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Cci, inChart.IndicatorColors[0], false)
                }
            } else if inChart.ShowIndicator == "BBI" {
                if inChart.SelectShape == inChart.ShowIndicator{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Bbi, inChart.IndicatorColors[0], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Bbi, inChart.IndicatorColors[0], false)
                }   
            } else if inChart.ShowIndicator == "TRIX" {
                if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "TRIX"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Trix, inChart.IndicatorColors[0], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Trix, inChart.IndicatorColors[0], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "TRIXMA"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.TrixMa, inChart.IndicatorColors[1], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.TrixMa, inChart.IndicatorColors[1], false)
                }
            } else if inChart.ShowIndicator == "DMA" {
                if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "DIF"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Dma1, inChart.IndicatorColors[0], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Dma1, inChart.IndicatorColors[0], false)
                }
				if inChart.SelectShape == inChart.ShowIndicator && inChart.SelectShapeEx == "DIFMA"{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Dma2, inChart.IndicatorColors[1], true)
                }else{
					DrawChartLines(chart, paint, clipRect, 2, inChart.Dma2, inChart.IndicatorColors[1], false)
                }
            }
        }
    }
    //绘制扩展线条
    if len(inChart.Shapes) > 0 {
        for i := 0; i < len(inChart.Shapes); i++ {
            shape := inChart.Shapes[i]
            if shape.ShapeType == "bar" {
                for j := inChart.FirstVisibleIndex; j <= lastValidIndex; j++ {
                    if len(shape.ShowHideDatas) > j && ConvertIntToStr(int(shape.ShowHideDatas[j])) == "0" {
                        continue
                    }
                    x := GetChartX(chart, j)
                    y1 := 0.0
                    if shape.LeftOrRight {
                        y1 = GetChartY(chart, shape.DivIndex, shape.Datas[j])
                    } else {
                        y1 = GetChartYInRight(chart, shape.DivIndex, shape.Datas[j])
                    }
                    if shape.Style != "2color" {
                        y2 := 0.0
                        if shape.LeftOrRight {
                            y2 = GetChartY(chart, shape.DivIndex, shape.Datas2[j])
                        } else {
                            y2 = GetChartYInRight(chart, shape.DivIndex, shape.Datas2[j])
                        }
                        if y1 >= y2 {
                            paint.FillRect(shape.Color, x - cWidth, y2, x + cWidth, y1)
                        }else {
                            paint.FillRect(shape.Color, x - cWidth, y1, x + cWidth, y2)
                        }
                    } else {
                        y2 := 0.0
                        if shape.LeftOrRight {
                            y2 = GetChartY(chart, shape.DivIndex, 0)
                        } else {
                            y2 = GetChartYInRight(chart, shape.DivIndex, 0)
                        }
                        if y1 >= y2 {
                            paint.DrawLine(shape.Color2, 1, 0, x, y1, x, y2)
                        }else {
                            paint.DrawLine(shape.Color, 1, 0, x, y1, x, y2)
                        }
                        if j == lastValidIndex {
                            paint.DrawLine(shape.Color2, 1, 0, inChart.LeftVScaleWidth, y2, chart.Size.Cx - inChart.RightVScaleWidth, y2)
                        }
                    }
                }
            }else if shape.ShapeType == "text"{
                for j := inChart.FirstVisibleIndex; j <= lastValidIndex; j++ {
                    x := GetChartX(chart, j)
                    if shape.Datas[j] != 0 {
                        y1 := 0.0
                        if shape.LeftOrRight {
                            y1 = GetChartY(chart, shape.DivIndex, shape.Value)
                        } else {
                            y1 = GetChartYInRight(chart, shape.DivIndex, shape.Value)
                        }
                        DrawText := shape.Text
                        tSize := paint.TextSize(DrawText, "Default,14")
                        paint.DrawText(DrawText, shape.Color, "Default,14", x - tSize.Cx / 2, y1 - tSize.Cy / 2)
                    }
                }
            }else {
                if shape.LeftOrRight {
                    if inChart.SelectShape == shape.ShapeName{
                        DrawChartLines(chart, paint, clipRect, shape.DivIndex, shape.Datas, shape.Color, true)
                    }else{
                        DrawChartLines(chart, paint, clipRect, shape.DivIndex, shape.Datas, shape.Color, false)
                    }
                } else {
                    if inChart.SelectShape == shape.ShapeName{
                        DrawChartLinesInRight(chart, paint, clipRect, shape.DivIndex, shape.Datas, shape.Color, true)
                    }else{
                        DrawChartLinesInRight(chart, paint, clipRect, shape.DivIndex, shape.Datas, shape.Color, false)
                    }
                }
            }
        }
    }
}

/*
* 获取数据
* chart:图表
*/
func CalcChartIndicator(chart *FCView) {
    inChart := chart.GetChart()
    ClearDataArr(chart)
    if len(inChart.Data) > 0{
        var closeArr []float64
        var highArr []float64
        var lowArr []float64
        if len(inChart.Data) > 0 {
            for i := 0; i < len(inChart.Data); i++ {
                closeArr = append(closeArr, inChart.Data[i].Close)
                highArr = append(highArr, inChart.Data[i].High)
                lowArr = append(lowArr, inChart.Data[i].Low)
            }
        }
        inChart.CloseArr = closeArr
        if inChart.MainIndicator == "BOLL" {
            GetBollData(chart, 20, closeArr)
        } else if inChart.MainIndicator == "MA" {
            inChart.Ma5 = MaValue(closeArr, 5)
            inChart.Ma10 = MaValue(closeArr, 10)
            inChart.Ma20 = MaValue(closeArr, 20)
            inChart.Ma30 = MaValue(closeArr, 30)
            inChart.Ma120 = MaValue(closeArr, 120)
            inChart.Ma250 = MaValue(closeArr, 250)
        }
        if inChart.ShowIndicator == "BIAS" {
            GetBIASData(chart, 6, 12, 24, closeArr)
        }else if inChart.ShowIndicator == "DMA"{
            GetDMAData(chart, 10, 50, closeArr)
        }else if inChart.ShowIndicator == "BBI"{
            GetBBIData(chart, closeArr, 3, 6, 12, 24)
        }else if inChart.ShowIndicator == "RSI"{
            GetRSIData(chart, 6, 12, 24, closeArr)
        }else if inChart.ShowIndicator == "ROC"{
            GetRocData(chart, 12, 6, closeArr)
        }else if inChart.ShowIndicator == "TRIX"{
            GetTRIXData(chart, 12, 9, closeArr)
        }else if inChart.ShowIndicator == "KDJ"{
            GetKDJData(chart, highArr, lowArr, closeArr, 9, 3, 3)
        }else if inChart.ShowIndicator == "WR"{
            GetWRData(chart, highArr, lowArr, closeArr, 5, 10)
        }else if inChart.ShowIndicator == "CCI"{
            GetCCIData(chart, highArr, lowArr, 14, closeArr)
        }else if inChart.ShowIndicator == "MACD" {
            //缓存MACD数据
            inChart.Allema12 = append(inChart.Allema12, closeArr[0])
            inChart.Allema26 = append(inChart.Allema26, closeArr[0])
            inChart.Alldeaarr = append(inChart.Alldeaarr, 0)
            for i := 1; i < len(closeArr); i++ {
                lastEMA := GetEMA(12, closeArr[i], inChart.Allema12[i - 1])
                lastEMA2 := GetEMA(26, closeArr[i], inChart.Allema26[i - 1])
                inChart.Allema12 = append(inChart.Allema12, lastEMA)
                inChart.Allema26 = append(inChart.Allema26, lastEMA2)
            }
            inChart.Alldifarr = getDIF(inChart.Allema12, inChart.Allema26)
            for i := 1; i < len(inChart.Alldifarr); i++ {
                inChart.Alldeaarr = append(inChart.Alldeaarr, inChart.Alldeaarr[i - 1] * 8 / 10 + inChart.Alldifarr[i] * 2 / 10)
            }
            inChart.Allmacdarr = GetMACD(inChart.Alldifarr, inChart.Alldeaarr)
        }
    }
    if chart.GetPaint().OnCalculateMaxMin != nil{
        chart.GetPaint().OnCalculateMaxMin(chart)
    }else{
        CalculateChartMaxMin(chart)
    }
}

/*
* 计算EMA
* n:周期
* value:当前数据
* lastEMA:上期数据
*/
func GetEMA(n int, value float64, lastEMA float64)(float64) {
    return(value * 2 + lastEMA * float64(n - 1)) / float64(n + 1)
}

/*
* 计算MACD
* dif:DIF数据
* dea:DEA数据
*/
func GetMACD(dif []float64, dea []float64)([]float64) {
    var result []float64
	length := len(dif)
	for i := 0; i < length; i++ {
			result = append(result, (dif[i] - dea[i]) * 2.0)
	}
	return result
}

/*
* 计算DIF
* close12:12日数据
* close26:26日数据
*/
func getDIF(close12 []float64, close26 []float64) ([]float64) {
    var result []float64
    for i := 0; i < len(close12); i++ {
        result = append(result, close12[i] - close26[i])
    }
    return result
}

/*
* 清除缓存数据方法
* chart:图表
*/
func ClearDataArr(chart *FCView) {
    inChart := chart.GetChart()
    var allema12[] float64
    inChart.Allema12 = allema12
    var allema26[] float64
    inChart.Allema26 = allema26
    var alldifarr[] float64
    inChart.Alldifarr = alldifarr
    var alldeaarr[] float64
    inChart.Alldeaarr = alldeaarr
    var allmacdarr[] float64
    inChart.Allmacdarr = allmacdarr
    var bollUp[] float64
    inChart.BollUp = bollUp
    var bollDown[] float64
    inChart.BollDown = bollDown
    var bollMid[] float64
    inChart.BollMid = bollMid
    var bias1[] float64
    inChart.Bias1 = bias1
    var bias2[] float64
    inChart.Bias2 = bias2
    var bias3[] float64
    inChart.Bias3 = bias3
    var kdjK[] float64
    inChart.KdjK = kdjK
    var kdjD[] float64
    inChart.KdjD = kdjD
    var kdjJ[] float64
    inChart.KdjJ = kdjJ
    var rsi1[] float64
    inChart.Rsi1 = rsi1
    var rsi2[] float64
    inChart.Rsi2 = rsi2
    var rsi3[] float64
    inChart.Rsi3 = rsi3
    var roc[] float64
    inChart.Roc = roc
    var rocMa[] float64
    inChart.RocMa = rocMa
    var wr1[] float64
    inChart.Wr1 = wr1
    var wr2[] float64
    inChart.Wr2 = wr2
    var cci[] float64
    inChart.Cci = cci
    var bbi[] float64
    inChart.Bbi = bbi
    var trix[] float64
    inChart.Trix = trix
    var trixMa[] float64
    inChart.TrixMa = trixMa
    var dma1[] float64
    inChart.Dma1 = dma1
    var dma2[] float64
    inChart.Dma2 = dma2
    var ma5[] float64
    inChart.Ma5 = ma5
    var ma10[] float64
    inChart.Ma10 = ma10
    var ma20[] float64
    inChart.Ma20 = ma20
    var ma30[] float64
    inChart.Ma30 = ma30
    var ma120[] float64
    inChart.Ma120 = ma120
    var ma250[] float64
    inChart.Ma250 = ma250
}

/*
* 判断是否选中线条
* chart:图表
* mp:坐标
* divIndex:层索引
* datas:数据
* curIndex:当前索引
*/
func SelectLines(chart *FCView, mp FCPoint, divIndex int, datas []float64, curIndex int)(bool){
    inChart := chart.GetChart()
    if len(datas) > 0 {
        topY := GetChartY(chart, divIndex, datas[curIndex])
        if inChart.HScalePixel <= 1 {
            if mp.Y >= topY - 8 && mp.Y <= topY + 8 {
                return true
            }
        } else {
            index := curIndex
            scaleX := GetChartX(chart, index)
            judgeTop := 0.0
            judgeScaleX := scaleX
            if mp.X >= scaleX {
                leftIndex := curIndex + 1
                if curIndex < inChart.LastVisibleIndex {
                    rightValue := datas[leftIndex]
                    judgeTop = GetChartY(chart, divIndex, rightValue)
                }else {
                    judgeTop = topY
                }
            }else {
                judgeScaleX = scaleX - inChart.HScalePixel
                rightIndex := curIndex - 1
                if curIndex > 0 {
                    leftValue := datas[rightIndex]
                    judgeTop = GetChartY(chart, divIndex, leftValue)
                } else {
                    judgeTop = topY
                }
            }
            lineWidth := 4.0
            judgeX := 0.0
            judgeY := 0.0
            judgeW := 0.0
            judgeH := 0.0
            if judgeTop >= topY {
                judgeX = judgeScaleX
                judgeY = topY - 2 - lineWidth
                judgeW = inChart.HScalePixel
                if judgeTop - topY + lineWidth < 4{
                    judgeH = 4
                }else{
                    judgeH = judgeTop - topY + 4 + lineWidth
                }
            }else {
                judgeX = judgeScaleX
                judgeY = judgeTop - 2 - lineWidth / 2
                judgeW = inChart.HScalePixel
                if topY - judgeTop + lineWidth < 4{
                    judgeH = 4
                }else{
                    judgeH = topY - judgeTop + 4 + lineWidth
                }
            }
            if (mp.X >= judgeX && mp.X <= judgeX + judgeW && mp.Y >= judgeY && mp.Y <= judgeY + judgeH) {

                return true
            }
        }
    }
    return false
}

/*
* 判断是否在右轴选中线条
* chart:图表
* mp:坐标
* divIndex:层索引
* datas:数据
* curIndex:当前索引
*/
func SelectLinesInRight(chart *FCView, mp FCPoint, divIndex int, datas []float64, curIndex int)(bool){
    inChart := chart.GetChart()
    if len(datas) > 0 {
        topY := GetChartYInRight(chart, divIndex, datas[curIndex])
        if inChart.HScalePixel <= 1 {
            if mp.Y >= topY - 8 && mp.Y <= topY + 8 {
                return true
            }
        } else {
            index := curIndex
            scaleX := GetChartX(chart, index)
            judgeTop := 0.0
            judgeScaleX := scaleX
            if mp.X >= scaleX {
                leftIndex := curIndex + 1
                if curIndex < inChart.LastVisibleIndex {
                    rightValue := datas[leftIndex]
                    judgeTop = GetChartYInRight(chart, divIndex, rightValue)
                }else {
                    judgeTop = topY
                }
            }else {
                judgeScaleX = scaleX - inChart.HScalePixel
                rightIndex := curIndex - 1
                if curIndex > 0 {
                    leftValue := datas[rightIndex]
                    judgeTop = GetChartYInRight(chart, divIndex, leftValue)
                } else {
                    judgeTop = topY
                }
            }
            lineWidth := 4.0
            judgeX := 0.0
            judgeY := 0.0
            judgeW := 0.0
            judgeH := 0.0
            if judgeTop >= topY {
                judgeX = judgeScaleX
                judgeY = topY - 2 - lineWidth
                judgeW = inChart.HScalePixel
                if judgeTop - topY + lineWidth < 4{
                    judgeH = 4
                }else{
                    judgeH = judgeTop - topY + 4 + lineWidth
                }
            }else {
                judgeX = judgeScaleX
                judgeY = judgeTop - 2 - lineWidth / 2
                judgeW = inChart.HScalePixel
                if topY - judgeTop + lineWidth < 4{
                    judgeH = 4
                }else{
                    judgeH = topY - judgeTop + 4 + lineWidth
                }
            }
            if mp.X >= judgeX && mp.X <= judgeX + judgeW && mp.Y >= judgeY && mp.Y <= judgeY + judgeH {

                return true
            }
        }
    }
    return false
}

/*
* 判断是否选中图形
* chart:图表
* mp:坐标
*/
func SelectShape(chart *FCView, mp FCPoint) {
    inChart := chart.GetChart()
    inChart.SelectShape = ""
    inChart.SelectShapeEx = ""
    candleHeight := GetCandleDivHeight(chart)
    volHeight := GetVolDivHeight(chart)
    indHeight := GetIndDivHeight(chart)
    index := GetChartIndex(chart, mp)
    if index != -1{
        if mp.Y >= candleHeight + volHeight && mp.Y <= candleHeight + volHeight + indHeight {
            if inChart.ShowIndicator == "MACD" {
                if SelectLines(chart, mp, 2, inChart.Allmacdarr, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "MACD"
                }
                if SelectLines(chart, mp, 2, inChart.Alldifarr, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "DIF"
                }else if SelectLines(chart, mp, 2, inChart.Alldeaarr, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "DEA"
                }
            } else if inChart.ShowIndicator == "KDJ" {
                if SelectLines(chart, mp, 2, inChart.KdjK, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "K"
                }else if SelectLines(chart, mp, 2, inChart.KdjD, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "D"
                } else if SelectLines(chart, mp, 2, inChart.KdjJ, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "J"
                }
            } else if inChart.ShowIndicator == "RSI" {
                if SelectLines(chart, mp, 2, inChart.Rsi1, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "6"
                }else if SelectLines(chart, mp, 2, inChart.Rsi2, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "12"
                } else if SelectLines(chart, mp, 2, inChart.Rsi3, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "24"
                }
            }else if inChart.ShowIndicator == "BIAS" {
                if SelectLines(chart, mp, 2, inChart.Bias1, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "1"
                }else if SelectLines(chart, mp, 2, inChart.Bias2, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "2"
                } else if SelectLines(chart, mp, 2, inChart.Bias3, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "3"
                }
            }else if inChart.ShowIndicator == "ROC" {
                if SelectLines(chart, mp, 2, inChart.Roc, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "ROC"
                }else if SelectLines(chart, mp, 2, inChart.RocMa, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "ROCMA"
                }
            } else if inChart.ShowIndicator == "WR" {
                if SelectLines(chart, mp, 2, inChart.Wr1, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "1"
                }else if SelectLines(chart, mp, 2, inChart.Wr2, index) {
                    inChart.SelectShape = "WR"
                    inChart.SelectShapeEx = "2"
                }
            } else if inChart.ShowIndicator == "CCI" {
                if SelectLines(chart, mp, 2, inChart.Cci, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                }
            } else if inChart.ShowIndicator == "BBI" {
                if SelectLines(chart, mp, 2, inChart.Bbi, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                }
            } else if inChart.ShowIndicator == "TRIX" {
                if SelectLines(chart, mp, 2, inChart.Trix, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "TRIX"
                }else if SelectLines(chart, mp, 2, inChart.TrixMa, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "TRIXMA"
                }
            } else if inChart.ShowIndicator == "DMA" {
                if SelectLines(chart, mp, 2, inChart.Dma1, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "DIF"
                }else if SelectLines(chart, mp, 2, inChart.Dma2, index) {
                    inChart.SelectShape = inChart.ShowIndicator
                    inChart.SelectShapeEx = "DIFMA"
                }
            }
        }else if mp.Y >= candleHeight && mp.Y <= candleHeight + volHeight {
            volY := GetChartY(chart, 1, inChart.Data[index].Volume)
            zeroY := GetChartY(chart, 1, 0)
            if mp.Y >= math.Min(volY, zeroY) && mp.Y <= math.Max(volY, zeroY) {
                inChart.SelectShape = "VOL"
            }
        }else if mp.Y >= 0 && mp.Y <= candleHeight {
            isTrend :=  false
            if inChart.Cycle == "trend"{
                isTrend = true
            }
            if !isTrend {
                if inChart.MainIndicator == "BOLL" {
                    if SelectLines(chart, mp, 0, inChart.BollMid, index) {
                        inChart.SelectShape = inChart.MainIndicator
                        inChart.SelectShapeEx = "MID"
                    }else if SelectLines(chart, mp, 0, inChart.BollUp, index) {
                        inChart.SelectShape = inChart.MainIndicator
                        inChart.SelectShapeEx = "UP"
                    } else if SelectLines(chart, mp, 0, inChart.BollDown, index) {
                        inChart.SelectShape = inChart.MainIndicator
                        inChart.SelectShapeEx = "DOWN"
                    }
                } else if inChart.MainIndicator == "MA" {
                    if SelectLines(chart, mp, 0, inChart.Ma5, index) {
                        inChart.SelectShape = inChart.MainIndicator
                        inChart.SelectShapeEx = "5"
                    }else if SelectLines(chart, mp, 0, inChart.Ma10, index) {
                        inChart.SelectShape = inChart.MainIndicator
                        inChart.SelectShapeEx = "10"
                    }else if SelectLines(chart, mp, 0, inChart.Ma20, index) {
                        inChart.SelectShape = inChart.MainIndicator
                        inChart.SelectShapeEx = "20"
                    }else if SelectLines(chart, mp, 0, inChart.Ma30, index) {
                        inChart.SelectShape = inChart.MainIndicator
                        inChart.SelectShapeEx = "30"
                    }else if SelectLines(chart, mp, 0, inChart.Ma120, index) {
                        inChart.SelectShape = inChart.MainIndicator
                        inChart.SelectShapeEx = "120"
                    }else if SelectLines(chart, mp, 0, inChart.Ma250, index) {
                        inChart.SelectShape = inChart.MainIndicator
                        inChart.SelectShapeEx = "250"
                    }
                }
            }
            if inChart.SelectShape == "" {
                highY := GetChartY(chart, 0, inChart.Data[index].High)
                lowY := GetChartY(chart, 0, inChart.Data[index].Low)
                if isTrend {
                    if SelectLines(chart, mp, 0, inChart.CloseArr, index) {
                        inChart.SelectShape = "CANDLE"
                    }
                }else {
                    if mp.Y >= math.Min(lowY, highY) && mp.Y <= math.Max(lowY, highY) {
                        inChart.SelectShape = "CANDLE"
                    }
                }
            }
        }
        if len(inChart.Shapes) > 0 {
            for i := 0; i < len(inChart.Shapes); i++ {
                shape := inChart.Shapes[i]
                if shape.LeftOrRight {
                    if SelectLines(chart, mp, shape.DivIndex, shape.Datas, index) {
                        inChart.SelectShape = shape.ShapeName
                        break
                    }
                } else {
                    if SelectLinesInRight(chart, mp, shape.DivIndex, shape.Datas, index) {
                        inChart.SelectShape = shape.ShapeName
                        break
                    }
                }
            }
        }
    }
}

/*
* 鼠标点击实现方法
* view: 图层
* firstTouch:是否第一次触摸
* firstPoint:第一次触摸的坐标
* secondTouch:是否第二次触摸
* secondPoint:第二次触摸的坐标
* clicks:点击次数
*/
func OnClickDefault(view *FCView, firstTouch bool, firstPoint FCPoint, secondTouch bool, secondPoint FCPoint, clicks int){
    if view.ViewType == "tabbutton" {
        tabView := view.GetParent()
        intTabView := tabView.GetTabView()
        if len(intTabView.TabPages) > 0{
            for i := 0; i < len(intTabView.TabPages); i++ {
                inTabPage := intTabView.TabPages[i].GetTabPage()
                if inTabPage.GetHeaderButton() == view {
                    SelectTabPage(tabView, intTabView.TabPages[i])
                    break
                }
            }
        }
        InvalidateView(tabView)
    }else if view.ViewType == "radiobutton" {
        ClickRadioButton(view, firstPoint)
        Invalidate(view.GetPaint())
    }else if view.ViewType == "checkbox" {
        ClickCheckBox(view, firstPoint)
        InvalidateView(view.GetParent())
    }else if view.ViewType == "menuitem"{
	    ClickMenuItem(view)
	}else if view.ViewType == "combobox"{
		ClickComboBox(view)
    }
}

/*
* 重绘背景的实现方法
* view:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func OnPaintDefault(view *FCView, paint *FCPaint, clipRect FCRect) {
    if view.ViewType == "chart"{
        DrawChart(view, paint, clipRect)
    }else if view.ViewType == "div" || view.ViewType == "layout" || view.ViewType == "tabpage" {
        DrawDiv(view, paint, clipRect)
    }else if view.ViewType == "grid" {
        DrawDiv(view, paint, clipRect)
        DrawGrid(view, paint, clipRect)
    }else if view.ViewType == "tree" {
        DrawDiv(view, paint, clipRect)
        DrawTree(view, paint, clipRect)
    }else if view.ViewType == "calendar"{
        DrawCalendar(view, paint)
    }else if view.ViewType == "label" {
        if view.TextColor != "none" {
            tSize := paint.TextSize(view.Text, view.Font)
            paint.DrawText(view.Text, view.TextColor, view.Font, 0, (view.Size.Cy - tSize.Cy) / 2)
        }
    }else if view.ViewType == "radiobutton" {
        DrawRadioButton(view, paint, clipRect)
    }else if view.ViewType == "checkbox" {
        DrawCheckBox(view, paint, clipRect)
    }else if view.ExView{
        paint.GdiPlus.paintView(view.ViewName, 0, 0, view.Size.Cx, view.Size.Cy)
    }else if view.ViewType == "menuitem"{
		DrawMenuItem(view, paint, clipRect)
    }else if view.ViewType == "combobox"{
		DrawComboBox(view, paint, clipRect)
    }else{
        DrawButton(view, paint, clipRect)
    }
}

/*
* 重绘边框的实现方法
* view:视图
* paint:绘图对象
* clipRect:裁剪区域
*/
func OnPaintBorderDefault(view *FCView, paint *FCPaint, clipRect FCRect) {
    if view.ViewType == "grid" {
        DrawGridScrollBar(view, paint, clipRect)
        DrawDivBorder(view, paint, clipRect)
    }else if view.ViewType == "tree"{
        DrawTreeScrollBar(view, paint, clipRect)
        DrawDivBorder(view, paint, clipRect)
    }else if view.ViewType == "div" || view.ViewType == "layout" || view.ViewType == "menu" {
        DrawDivScrollBar(view, paint, clipRect)
        DrawDivBorder(view, paint, clipRect)
    }else if view.ViewType == "tabpage" {
        DrawDivBorder(view, paint, clipRect)
    }else if view.ViewType == "tabview" {
        DrawTabViewBorder(view, paint, clipRect)
    } else if view.ViewType == "textbox" {
        DrawDivBorder(view, paint, clipRect)
    }
}

/*
*视图的鼠标移动方法
*view 视图
*mp 坐标
*buttons 按钮 0未按下 1左键 2右键
*clicks 点击次数
*delta 滚轮值
*/
func OnMouseMoveDefault(view *FCView, mp FCPoint, buttons int, clicks int, delta int){
	firstTouch := false
	secondTouch := false
	firstPoint := mp
	secondPoint := mp
	if buttons == 1{
		firstTouch = true
    }else if buttons == 2{
        secondTouch = true
    }
	if view.ViewType == "grid"{
		TouchMoveGrid(view, firstTouch, firstPoint, secondTouch, secondPoint)
		InvalidateView(view)
    }else if view.ViewType == "tree"{
		TouchMoveTree(view, firstTouch, firstPoint, secondTouch, secondPoint)
		InvalidateView(view)
	}else if view.ViewType == "chart"{
		TouchMoveChart(view, firstTouch, firstPoint, secondTouch, secondPoint)
		InvalidateView(view)
	}else if view.ViewType == "div" || view.ViewType =="layout" || view.ViewType =="menu"{
		TouchMoveDiv(view, firstTouch, firstPoint, secondTouch, secondPoint)
		InvalidateView(view)
	}else if view.ViewType == "button"{
		InvalidateView(view)
    }else if (view.ViewType == "menuitem"){
		TouchMoveMenuItem(view)
    }else{
        InvalidateView(view)
    }
}

/*
*视图的鼠标按下方法
*view 视图
*mp 坐标
*buttons 按钮 0未按下 1左键 2右键
*clicks 点击次数
*delta 滚轮值
*/
func OnMouseDownDefault(view *FCView, mp FCPoint, buttons int, clicks int, delta int){
	firstTouch := false
	secondTouch := false
	firstPoint := mp
	secondPoint := mp
	if buttons == 1{
		firstTouch = true
    }else if buttons == 2{
        secondTouch = true
    }
	if view.ViewType == "grid"{
		TouchDownGrid(view, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
		InvalidateView(view)
    }else if view.ViewType == "tree"{
		TouchDownTree(view, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
		InvalidateView(view)
    }else if view.ViewType == "div" || view.ViewType =="layout" || view.ViewType =="menu"{
		TouchDownDiv(view, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
		InvalidateView(view)
    }else if view.ViewType == "button"{
		InvalidateView(view)
    }else if view.ViewType == "calendar"{
		ClickCalendar(view, firstPoint)
    }else if view.ViewType == "chart"{
		TouchDownChart(view, firstTouch, firstPoint, secondTouch, secondPoint)
		InvalidateView(view)
    }
}

/*
*视图的鼠标抬起方法
*view 视图
*mp 坐标
*buttons 按钮 0未按下 1左键 2右键
*clicks 点击次数
*delta 滚轮值
*/
func OnMouseUpDefault(view *FCView, mp FCPoint, buttons int, clicks int, delta int){
	firstTouch := false
	secondTouch := false
	firstPoint := mp
	secondPoint := mp
	if buttons == 1{
		firstTouch = true
    }else if buttons == 2{
        secondTouch = true
    }
	if view.ViewType == "grid"{
		TouchUpGrid(view, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
    }else if view.ViewType == "tree"{
		TouchUpTree(view, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
    }else if view.ViewType == "div" || view.ViewType =="layout" || view.ViewType =="menu"{
		TouchUpDiv(view, firstTouch, firstPoint, secondTouch, secondPoint, clicks)
    }else if view.ViewType == "chart"{
        chart := view.GetChart()
		chart.FirstTouchIndexCacheChart = -1
		chart.SecondTouchIndexCacheChart = -1
    }
    InvalidateView(view)
}

/*
*视图的鼠标滚动方法
*view 视图
*mp 坐标
*buttons 按钮 0未按下 1左键 2右键
*clicks 点击次数
*delta 滚轮值
*/
func OnMouseWheelDefault(view *FCView, mp FCPoint, buttons int, clicks int, delta int){
	if view.ViewType == "grid"{
		TouchWheelGrid(view, delta)
		InvalidateView(view)
    }else if view.ViewType == "tree"{
		TouchWheelTree(view, delta)
		InvalidateView(view)
    }else if view.ViewType == "div" || view.ViewType =="layout" || view.ViewType =="menu"{
		TouchWheelDiv(view, delta)
		InvalidateView(view)
    }else if view.ViewType == "chart"{
		if delta > 0{
			ZoomOutChart(view)
        }else if delta < 0{
			ZoomInChart(view)
        }
		InvalidateView(view)
    }
}

/*
* 重绘视图
* views:视图集合
* paint:绘图对象
* rect:区域
*/
func RenderViews(views []*FCView, paint *FCPaint, rect FCRect) {
    viewsSize := len(views)
    if viewsSize > 0{
        for i := 0; i < viewsSize; i++ {
            view := views[i]
            if !rect.IsNotEmpty {
                noneRect := CreateRect(0, 0, 0, 0)
                noneRect.IsNotEmpty = false
                if len(view.Views) > 0 {
                    subViewsSize := len(view.Views)
                    if subViewsSize > 0 {
                        RenderViews(view.Views, paint, noneRect)
                    }
                }
                view.ClipRect = noneRect
                continue
            }
            if !view.TopMost && IsPaintVisible(view) {
                clx := ClientX(view)
                cly := ClientY(view)
                DrawRect := CreateRect(0, 0, view.Size.Cx, view.Size.Cy)
                clipRect := CreateRect(clx, cly, clx + view.Size.Cx, cly + view.Size.Cy)
                destRect := CreateRect(0, 0, 0, 0)
                if GetIntersectRect(&destRect, rect, clipRect) > 0{
                    view.ClipRect = destRect
                    paint.SetOffset(clx, cly)
                    paint.SetClip(destRect.Left - clx, destRect.Top - cly, destRect.Right - clx, destRect.Bottom - cly)
                    if paint.OnPaint != nil{
                        paint.OnPaint(view, paint, DrawRect)
                    }else{
                        OnPaintDefault(view, paint, DrawRect)
                    }
                    if len(view.Views) > 0 {
                        subViewsSize := len(view.Views)
                        if subViewsSize > 0 {
                            RenderViews(view.Views, paint, destRect)
                        }
                    }
                    paint.SetOffset(clx, cly)
                    paint.SetClip(destRect.Left - clx, destRect.Top - cly, destRect.Right - clx, destRect.Bottom - cly)
                    if paint.OnPaintBorder != nil{
                        paint.OnPaintBorder(view, paint, DrawRect)
                    }else{
                        OnPaintBorderDefault(view, paint, DrawRect)
                    }
                } else {
                    noneRect := CreateRect(0, 0, 0, 0)
                    if len(view.Views) > 0 {
                        subViewsSize := len(view.Views)
                        if subViewsSize > 0 {
                            RenderViews(view.Views, paint, noneRect)
                        }
                    }
                    view.ClipRect = noneRect
                }
            }
        }
        for i := 0; i < viewsSize; i++ {
            view := views[i]
            if !rect.IsNotEmpty {
                noneRect := CreateRect(0, 0, 0, 0)
                noneRect.IsNotEmpty = false
                if len(view.Views) > 0 {
                    subViewsSize := len(view.Views)
                    if subViewsSize > 0 {
                        RenderViews(view.Views, paint, noneRect)
                    }
                }
                view.ClipRect = noneRect
                continue
            }
            if view.TopMost && IsPaintVisible(view) {
                clx := ClientX(view)
                cly := ClientY(view)
                DrawRect := CreateRect(0, 0, view.Size.Cx, view.Size.Cy)
                clipRect := CreateRect(clx, cly, clx + view.Size.Cx, cly + view.Size.Cy)
                destRect := CreateRect(0, 0, 0, 0)
                if GetIntersectRect(&destRect, rect, clipRect) > 0{ 
                    view.ClipRect = destRect
                    paint.SetOffset(clx, cly)
                    paint.SetClip(destRect.Left - clx, destRect.Top - cly, destRect.Right - clx, destRect.Bottom - cly)
                    if paint.OnPaint != nil{
                        paint.OnPaint(view, paint, DrawRect)
                    }else{
                        OnPaintDefault(view, paint, DrawRect)
                    }
                    if len(view.Views) > 0 {
                        subViewsSize := len(view.Views)
                        if subViewsSize > 0 {
                            RenderViews(view.Views, paint, destRect)
                        }
                    }
                    paint.SetOffset(clx, cly)
                    paint.SetClip(destRect.Left - clx, destRect.Top - cly, destRect.Right - clx, destRect.Bottom - cly)
                    if paint.OnPaintBorder != nil{
                        paint.OnPaintBorder(view, paint, DrawRect)
                    }else{
                        OnPaintBorderDefault(view, paint, DrawRect)
                    }
                } else {
                    noneRect := CreateRect(0, 0, 0, 0)
                    if len(view.Views) > 0 {
                        subViewsSize := len(view.Views)
                        if subViewsSize > 0 {
                            RenderViews(view.Views, paint, noneRect)
                        }
                    }
                    view.ClipRect = noneRect
                }
            }
        }
    }
}

/*
*鼠标移动方法
*mp 坐标
*buttons 按钮 0未按下 1左键 2右键
*clicks 点击次数
*delta 滚轮值
*paint 绘图对象
*/
func HandleMouseMove(mp FCPoint, buttons int, clicks int, delta int, paint *FCPaint){
    touchDownView := paint.GetTouchDownView()
    draggingView := paint.GetDraggingView()
    if touchDownView.IsNotEmpty{
		cmpPoint := CreatePoint(mp.X - ClientX(touchDownView), mp.Y - ClientY(touchDownView))
        if paint.OnMouseMove != nil{
		    paint.OnMouseMove(touchDownView, cmpPoint, buttons, clicks, 0)
        }else{
            OnMouseMoveDefault(touchDownView, cmpPoint, buttons, clicks, 0)
        }
        focusedView := paint.GetFocusedView()
		if !paint.IsDoubleClick{
			if focusedView.IsNotEmpty && focusedView.ExView{
				paint.GdiPlus.mouseMoveView(focusedView.ViewName, cmpPoint.X, cmpPoint.Y, 1, 1)
				InvalidateView(focusedView)	
            }
        }
        if touchDownView.ResizePoint != -1{
            newBounds := CreateRect(touchDownView.StartRect.Left, touchDownView.StartRect.Top, touchDownView.StartRect.Right, touchDownView.StartRect.Bottom)
            newBounds = WindowResize(newBounds, touchDownView.ResizePoint, mp, paint.TouchDownPoint)
            touchDownView.Location = CreatePoint(newBounds.Left, newBounds.Top)
            touchDownView.Size = CreateSize(newBounds.Right - newBounds.Left, newBounds.Bottom - newBounds.Top)
            if paint.IsNotEmpty{
                InvalidateView(touchDownView.GetParent())
            }else{
                Invalidate(paint)
            }
        }else if touchDownView.AllowDrag{
			if math.Abs(mp.X - paint.TouchDownPoint.X) > 5 || math.Abs(mp.Y - paint.TouchDownPoint.Y) > 5{
				paint.DragBeginRect = CreateRect(touchDownView.Location.X, touchDownView.Location.Y, touchDownView.Location.X + touchDownView.Size.Cx, touchDownView.Location.Y + touchDownView.Size.Cy)
				paint.DragBeginPoint = CreatePoint(paint.TouchDownPoint.X, paint.TouchDownPoint.Y)
                paint.SetDraggingView(touchDownView)
                var pList []*FCView
				paint.TouchDownView = pList
            }
        }
    }else if draggingView.IsNotEmpty && buttons == 1{
		offsetX := mp.X - paint.DragBeginPoint.X
		offsetY := mp.Y - paint.DragBeginPoint.Y
		newBounds := CreateRect(paint.DragBeginRect.Left + offsetX, paint.DragBeginRect.Top + offsetY, paint.DragBeginRect.Right + offsetX, paint.DragBeginRect.Bottom + offsetY)
		draggingView.Location = CreatePoint(newBounds.Left, newBounds.Top)
		if draggingView.GetParent().IsNotEmpty && draggingView.GetParent().ViewType == "split"{
			ResetSplitLayoutDiv(draggingView.GetParent())
            if paint.OnUpdateView != nil{
                paint.OnUpdateView(draggingView.GetParent().Views)
            }else{
                UpdateViewDefault(draggingView.GetParent().Views)
            }
        }
		if draggingView.GetParent().IsNotEmpty{
			InvalidateView(draggingView.GetParent())
        }else{
			Invalidate(paint)
        }
    }else{
		topViews := paint.Views
		view := FindView(mp, topViews)
		cmpPoint := CreatePoint(mp.X - ClientX(view), mp.Y - ClientY(view))
		if view.IsNotEmpty{
			oldMouseMoveView := paint.GetTouchMoveView()
            paint.SetTouchMoveView(view)
			if oldMouseMoveView.IsNotEmpty && oldMouseMoveView != view{
                if paint.OnMouseLeave != nil{
                    paint.OnMouseLeave(oldMouseMoveView, cmpPoint, buttons, clicks, 0)
                }
                InvalidateView(oldMouseMoveView)
            }
			if !oldMouseMoveView.IsNotEmpty || oldMouseMoveView != view{
                if paint.OnMouseEnter != nil{
                    paint.OnMouseEnter(view, cmpPoint, buttons, clicks, 0)	
                }
                paint.GdiPlus.setCursor(view.Cursor)
            }	
            if paint.OnMouseMove != nil{
                paint.OnMouseMove(view, cmpPoint, buttons, clicks, 0)
            }else{
                OnMouseMoveDefault(view, cmpPoint, buttons, clicks, 0)
            }
        }
    }
}

/*
*鼠标按下方法
*mp 坐标
*buttons 按钮 0未按下 1左键 2右键
*clicks 点击次数
*delta 滚轮值
*paint 绘图对象
*/
func HandleMouseDown(mp FCPoint, buttons int, clicks int, delta int, paint *FCPaint){
    if clicks == 2{
		paint.IsDoubleClick = true
    }else{
		paint.IsDoubleClick = false
    }
	paint.CancelClick = false
	paint.TouchDownPoint = mp
	topViews := paint.Views
	touchDownView := FindView(mp, topViews)
    paint.SetTouchDownView(touchDownView)
	if touchDownView.IsNotEmpty{
        CheckShowMenu(paint)
        focusedView := paint.GetFocusedView()
		if focusedView.IsNotEmpty && focusedView != touchDownView && focusedView.ExView{
			paint.GdiPlus.unFocusView(focusedView.ViewName)
			InvalidateView(focusedView)		
        }
        paint.SetFocusedView(touchDownView)
		cmpPoint := CreatePoint(mp.X - ClientX(touchDownView), mp.Y - ClientY(touchDownView))
        if paint.OnMouseDown != nil{
            paint.OnMouseDown(touchDownView, cmpPoint, buttons, clicks, 0)
        }else{
            OnMouseDownDefault(touchDownView, cmpPoint, buttons, clicks, 0)
        }
		if focusedView.IsNotEmpty && focusedView.ExView{
			paint.GdiPlus.focusView(focusedView.ViewName)
			paint.GdiPlus.mouseDownView(focusedView.ViewName, cmpPoint.X, cmpPoint.Y, buttons, clicks)
			InvalidateView(focusedView)
        }
        if touchDownView.AllowResize{
            touchDownView.ResizePoint = GetResizeState(touchDownView, cmpPoint)
            if touchDownView.ResizePoint != -1{
                touchDownView.StartRect = CreateRect(touchDownView.Location.X, touchDownView.Location.Y, touchDownView.Location.X + touchDownView.Size.Cx,
                    touchDownView.Location.Y + touchDownView.Size.Cy)
            }
        }
    }
}

/*
*鼠标抬起方法
*mp 坐标
*buttons 按钮 0未按下 1左键 2右键
*clicks 点击次数
*delta 滚轮值
*paint 绘图对象
*/
func HandleMouseUp(mp FCPoint, buttons int, clicks int, delta int, paint *FCPaint){
	paint.IsDoubleClick = false
    touchDownView := paint.GetTouchDownView()
	if touchDownView.IsNotEmpty{
		cmpPoint := CreatePoint(mp.X - ClientX(touchDownView), mp.Y - ClientY(touchDownView))
		topViews := paint.Views
		view := FindView(mp, topViews)
		if view.IsNotEmpty && view == touchDownView{
			if !paint.CancelClick{
                if paint.OnClick != nil{
                    paint.OnClick(touchDownView, true, cmpPoint, false, cmpPoint, clicks)
                }else{
                    OnClickDefault(touchDownView, true, cmpPoint, false, cmpPoint, clicks)
                }
            }	
        }
		if touchDownView.IsNotEmpty{
			mouseDownView := paint.GetTouchDownView()
            mouseDownView.ResizePoint = -1
            var pList[] *FCView
            paint.TouchDownView = pList
            var pList2[] *FCView
            paint.TouchMoveView = pList2
            if paint.OnMouseUp != nil{
			    paint.OnMouseUp(mouseDownView, cmpPoint, buttons, clicks, 0)
            }else{
                OnMouseUpDefault(mouseDownView, cmpPoint, buttons, clicks, 0)
            }
            focusedView := paint.GetFocusedView()
			if focusedView.IsNotEmpty && focusedView.ExView{
				focusedView.GetPaint().GdiPlus.focusView(focusedView.ViewName)
				focusedView.GetPaint().GdiPlus.mouseUpView(focusedView.ViewName, cmpPoint.X, cmpPoint.Y, buttons, clicks)
				InvalidateView(focusedView)
            }
        }
    }
    var pList2[] *FCView
    paint.DraggingView = pList2
}

/*
*鼠标滚动方法
*mp 坐标
*buttons 按钮 0未按下 1左键 2右键
*clicks 点击次数
*delta 滚轮值
*paint 绘图对象
*/
func HandleMouseWheel(mp FCPoint, buttons int, clicks int, delta int, paint *FCPaint){
	topViews := paint.Views
	view := FindView(mp, topViews)
	if view.IsNotEmpty{
		cmpPoint := CreatePoint(mp.X - ClientX(view), mp.Y - ClientY(view))
        if paint.OnMouseWheel != nil{
            paint.OnMouseWheel(view, cmpPoint, buttons, clicks, delta)
        }else{
            OnMouseWheelDefault(view, cmpPoint, buttons, clicks, delta)
        }
        if view.ExView{
            view.GetPaint().GdiPlus.mouseWheelView(view.ViewName, cmpPoint.X, cmpPoint.Y, buttons, clicks, delta)
	        InvalidateView(view)
        }
    }
}

/*
*获取视图文本
*view 视图
*atrName 属性名称
*/
func GetViewAttribute(view *FCView, atrName string)(string){
	viewText := view.GetPaint().GdiPlus.getAttribute(view.ViewName, atrName)
    return viewText
}

/*
*设置视图文本
*view 视图
*atrName 属性名称
*text 文本
*/
func SetViewAttribute(view *FCView, atrName string, text string){
    view.GetPaint().GdiPlus.setAttribute(view.ViewName, atrName, text)
}

/*
* 消息循环
*/
func WndProcDefault(paint *FCPaint, hwnd HWND, msg uint32, wParam, lParam uintptr) (result uintptr) {
    if msg == WM_DESTROY{
        if hwnd == mainWindowHandle{
            PostQuitMessageW32(0)
            return 1
        }
    }
    if hwnd == paint.HWnd{
        if msg == 0x0020{
            if(lParam == 33554433){
		        return 1
            }
        }else if msg == WM_ERASEBKGND{
			return 1
        }else if msg == WM_SIZE{
			rect := GetClientRectW32(paint.HWnd)
            wWidth := float64(rect.Right - rect.Left)
            wHeight := float64(rect.Bottom - rect.Top)
            if wWidth != paint.Size.Cx || wHeight != paint.Size.Cy{
                paint.Size = CreateSize(wWidth, wHeight)
                if paint.OnUpdateView != nil{
                    paint.OnUpdateView(paint.Views)
                }else{
                    UpdateViewDefault(paint.Views)
                }
            }
			Invalidate(paint)
        }else if msg == WM_LBUTTONDOWN{
			x, y, _ := GetCursorPosW32()
			sx, sy, _ := ScreenToClientW32(hwnd, x, y)
			mp := CreatePoint(float64(sx), float64(sy))
            mp.X /= paint.ScaleFactorX
            mp.Y /= paint.ScaleFactorY
            HandleMouseDown(mp, 1, 1, 0, paint)
        }else if msg == WM_RBUTTONDOWN{
			x, y, _ := GetCursorPosW32()
			sx, sy, _ := ScreenToClientW32(hwnd, x, y)
			mp := CreatePoint(float64(sx), float64(sy))
            mp.X /= paint.ScaleFactorX
            mp.Y /= paint.ScaleFactorY
            HandleMouseDown(mp, 2, 1, 0, paint)
        }else if msg == WM_LBUTTONDBLCLK{
			x, y, _ := GetCursorPosW32()
			sx, sy, _ := ScreenToClientW32(hwnd, x, y)
			mp := CreatePoint(float64(sx), float64(sy))
            mp.X /= paint.ScaleFactorX
            mp.Y /= paint.ScaleFactorY
			HandleMouseDown(mp, 1, 2, 0, paint)
		}else if msg == WM_RBUTTONDBLCLK{
			x, y, _ := GetCursorPosW32()
			sx, sy, _ := ScreenToClientW32(hwnd, x, y)
			mp := CreatePoint(float64(sx), float64(sy))
			HandleMouseDown(mp, 2, 2, 0, paint)
		}else if msg == WM_LBUTTONUP{
			x, y, _ := GetCursorPosW32()
			sx, sy, _ := ScreenToClientW32(hwnd, x, y)
			mp := CreatePoint(float64(sx), float64(sy))
            mp.X /= paint.ScaleFactorX
            mp.Y /= paint.ScaleFactorY
            if paint.IsDoubleClick{
                HandleMouseUp(mp, 1, 2, 0, paint)
            }else{
			    HandleMouseUp(mp, 1, 1, 0, paint)
            }
		}else if msg == WM_RBUTTONUP{
			x, y, _ := GetCursorPosW32()
			sx, sy, _ := ScreenToClientW32(hwnd, x, y)
			mp := CreatePoint(float64(sx), float64(sy))
            mp.X /= paint.ScaleFactorX
            mp.Y /= paint.ScaleFactorY
            if paint.IsDoubleClick{
                HandleMouseUp(mp, 2, 2, 0, paint)
            }else{
			    HandleMouseUp(mp, 2, 1, 0, paint)
            }
		}else if msg == WM_MOUSEWHEEL{
			x, y, _ := GetCursorPosW32()
			sx, sy, _ := ScreenToClientW32(hwnd, x, y)
			mp := CreatePoint(float64(sx), float64(sy))
            mp.X /= paint.ScaleFactorX
            mp.Y /= paint.ScaleFactorY
			if(wParam > 4000000000){
				HandleMouseWheel(mp, 0, 0, -1, paint)
            }else{
				HandleMouseWheel(mp, 0, 0, 1, paint)
            }
        }else if msg == WM_MOUSEMOVE{
			x, y, _ := GetCursorPosW32()
			sx, sy, _ := ScreenToClientW32(hwnd, x, y)
			mp := CreatePoint(float64(sx), float64(sy))
            mp.X /= paint.ScaleFactorX
            mp.Y /= paint.ScaleFactorY
			if wParam == 1{
				HandleMouseMove(mp, 1, 1, 0, paint)
            }else if wParam == 2{
				HandleMouseMove(mp, 2, 1, 0, paint)
            }else{
				HandleMouseMove(mp, 0, 0, 0, paint)
            }
        }else if msg == WM_PAINT{
			rect := GetClientRectW32(paint.HWnd)
            wWidth := float64(rect.Right - rect.Left)
            wHeight := float64(rect.Bottom - rect.Top)
            if wWidth != paint.Size.Cx || wHeight != paint.Size.Cy{
                paint.Size = CreateSize(wWidth, wHeight)
                if paint.OnUpdateView != nil{
                    paint.OnUpdateView(paint.Views)
                }else{
                    UpdateViewDefault(paint.Views)
                }
            }
			Invalidate(paint)
        }else if msg == 0x010F || msg == 0x0286 || msg == 0x0281{
            paint.GdiPlus.onMessage(int(hwnd), int(msg), int(wParam), int(lParam))
        }else if msg == WM_CHAR || msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN || msg == WM_KEYUP || msg == WM_SYSKEYUP{
            focusedView := paint.GetFocusedView()
			if focusedView.IsNotEmpty{
				if focusedView.ExView{
					paint.GdiPlus.onMessage(int(hwnd), int(msg), int(wParam), int(lParam))
					InvalidateView(focusedView)	
                }
                if msg == WM_KEYDOWN || msg == WM_SYSKEYDOWN{
                    if paint.OnKeyDown != nil{
                        paint.OnKeyDown(focusedView, int(wParam))
                    }
                }else if msg == WM_KEYUP || msg == WM_SYSKEYUP{
                    if paint.OnKeyUp != nil{
                        paint.OnKeyUp(focusedView, int(wParam))
                    }
                }else if msg == WM_CHAR{
                    if paint.OnChar != nil{
                        paint.OnChar(focusedView, int(wParam))
                    }
                }
            }
        }
    }
    return DefWindowProcW32(hwnd, msg, wParam, lParam)
}

/*
* 头部层
*/
type FCXmlNode struct {
    NodeName string //名称
    Content string //内容
    Children []*FCXmlNode //子节点
    IsNotEmpty bool
    Attributes map[string]string //属性
}

/*
* 初始化
*/
func CreateXmlNode()(*FCXmlNode){
    xmlNode := new(FCXmlNode)
    xmlNode.IsNotEmpty = true
    xmlNode.Attributes = make(map[string]string)
    return xmlNode
}

/*
* 设置属性
* view:视图
* node:xml节点
*/
func SetAttributeDefault(view *FCView, node *FCXmlNode) {
	if view.GetPaint().IsNotEmpty {
		if view.GetPaint().DefaultUIStyle == "dark" {
			view.BackColor = "rgb(0,0,0)"
			view.BorderColor = "rgb(100,100,100)"
			view.TextColor = "rgb(255,255,255)"
            view.ScrollBarColor = "rgb(100,100,100)"
		} else if view.GetPaint().DefaultUIStyle == "light" {
			view.BackColor = "rgb(255,255,255)"
			view.BorderColor = "rgb(150,150,150)"
			view.TextColor = "rgb(0,0,0)"
            view.ScrollBarColor = "rgb(200,200,200)"
		}
	}
    for key,value := range node.Attributes{
        name := strings.ToLower(key)
        if name == "location" {
            strs := strings.Split(value, ",")
            xStr := strs[0]
            yStr := strs[1]
            if strings.Contains(xStr, "%"){
                view.ExAttributes["leftstr"] = xStr
            }else{
                view.Location.X = ConvertToFloat64(xStr)
            }
            if strings.Contains(yStr, "%"){
                view.ExAttributes["topstr"] = yStr
            }else{
                view.Location.Y = ConvertToFloat64(yStr)
            }
		} else if name == "size" {
            strs := strings.Split(value, ",")
			xStr := strs[0]
            yStr := strs[1]
            if strings.Contains(xStr, "%"){
                view.ExAttributes["widthstr"] = xStr
            }else{
                view.Size.Cx = ConvertToFloat64(xStr)
            }
            if strings.Contains(yStr, "%"){
                view.ExAttributes["heightstr"] = yStr
            }else{
                view.Size.Cy = ConvertToFloat64(yStr)
            }
		} else if name == "text" {
			view.Text = value
		} else if name == "backcolor" {
			lowerStr := strings.ToLower(value)
			if strings.Contains(lowerStr, "rgb") {
				view.BackColor = value
			} else {
				view.BackColor = "none"
			}
		} else if name == "bordercolor" {
            lowerStr := strings.ToLower(value)
			if strings.Contains(lowerStr, "rgb") {
				view.BorderColor = value
			} else {
				view.BorderColor = "none"
			}
		} else if name == "textcolor" {
            lowerStr := strings.ToLower(value)
			if strings.Contains(lowerStr, "rgb") {
				view.TextColor = value
			} else {
				view.TextColor = "none"
			}
		} else if name == "layoutstyle"{
            if view.ViewType == "split"{
                view.GetSplitDiv().LayoutStyle = strings.ToLower(value)
            }else if view.ViewType == "layout"{
                view.GetLayoutDiv().LayoutStyle = strings.ToLower(value)
            }else if view.ViewType == "menu"{
                view.GetLayoutDiv().LayoutStyle = strings.ToLower(value)
            }
		} else if name == "align" {
			view.Align = strings.ToLower(value)
		} else if name == "cursor" {
			view.Cursor = strings.ToLower(value)
		} else if name == "vertical-align" {
			view.VerticalAlign = strings.ToLower(value)
		} else if name == "dock" {
			view.Dock = strings.ToLower(value)
		} else if name == "font" {
			view.Font = value
		} else if name == "headerheight" {
            if view.ViewType == "grid"{
                view.GetGrid().HeaderHeight = ConvertToFloat64(value)
            }else if view.ViewType == "tree"{
                view.GetTree().HeaderHeight = ConvertToFloat64(value)
            }
		}else if name == "cornerradius" {
            view.CornerRadius = ConvertToFloat64(value)
		}else if name == "borderwidth" {
            view.BorderWidth = ConvertToFloat64(value)
		} else if name == "splitmode" {
			view.GetSplitDiv().SplitMode = strings.ToLower(value)
		}else if name == "autowrap" {
            if strings.ToLower(value) == "true"{
                view.GetLayoutDiv().AutoWrap = true
            }else{
                view.GetLayoutDiv().AutoWrap = false
            }
		} else if name == "name" {
			view.ViewName = value
		} else if name == "tabindex" {
            view.TabIndex = ConvertToInt(value)
        }else if name == "tabstop" {
            if strings.ToLower(value) == "true"{
                view.TabStop = true
            }else{
                view.TabStop = false
            }
        }else if name == "enabled"{
        if strings.ToLower(value) == "true"{
            view.Enabled = true
        }else{
            view.Enabled = false
        }
		}else if name == "showvscrollbar"{
            if strings.ToLower(value) == "true"{
                view.ShowVScrollBar = true
            }else{
                view.ShowVScrollBar = false
            }
		} else if name == "showhscrollbar"{
            if strings.ToLower(value) == "true"{
                view.ShowHScrollBar = true
            }else{
                view.ShowHScrollBar = false
            }
		} else if name == "visible" {
            if strings.ToLower(value) == "true"{
                view.Visible = true
            }else{
                view.Visible = false
            }
		} else if name == "displayoffset" {
            if strings.ToLower(value) == "true"{
                view.DisplayOffset = true
            }else{
                view.DisplayOffset = false
            }
		} else if name == "checked" {
            if view.ViewType == "checkbox"{
                if strings.ToLower(value) == "true"{
                    view.GetCheckBox().Checked = true
                }else{
                    view.GetCheckBox().Checked = false
                }
            }else if view.ViewType == "radiobutton"{
                if strings.ToLower(value) == "true"{
                    view.GetRadioButton().Checked = true
                }else{
                    view.GetRadioButton().Checked = false
                }
            }
		} else if name == "buttonsize" {
            strs := strings.Split(value, ",")
            if view.ViewType == "checkbox"{
                view.GetCheckBox().ButtonSize = CreateSize(ConvertToFloat64(strs[0]), ConvertToFloat64(strs[1]))
            }else if view.ViewType == "radiobutton"{
                view.GetRadioButton().ButtonSize = CreateSize(ConvertToFloat64(strs[0]), ConvertToFloat64(strs[1]))
            }
		} else if name == "topmost" {
            if strings.ToLower(value) == "true"{
                view.TopMost = true
            }else{
                view.TopMost = false
            }
		} else if name == "selectedindex" {
            if view.ViewType == "combobox"{
			    view.GetComboBox().SelectedIndex = ConvertToInt(value)
            }
		} else if name == "src" {
			view.Src = value
		} else if name == "backimage"{
			view.BackImage = value
		} else if name == "groupname" {
			view.GetRadioButton().GroupName = value
		} else if name == "allowdragscroll" {
            if strings.ToLower(value) == "true"{
                view.AllowDragScroll = true
            }else{
                view.AllowDragScroll = false
            }
		} else if name == "allowpreviewsevent" {
            if strings.ToLower(value) == "true"{
                view.AllowPreviewsEvent = true
            }else{
                view.AllowPreviewsEvent = false
            }
		} else if name == "allowdrag" {
            if strings.ToLower(value) == "true"{
                view.AllowDrag = true
            }else{
                view.AllowDrag = false
            }
		} else if name == "allowresize" {
            if strings.ToLower(value) == "true"{
                view.AllowResize = true
            }else{
                view.AllowResize = false
            }
		}else if name == "Indent" {
			view.GetTree().Indent = ConvertToFloat64(value)
		} else if name == "showcheckbox" {
            if strings.ToLower(value) == "true"{
                view.GetTree().ShowCheckBox = true
            }else{
                view.GetTree().ShowCheckBox = false
            }
		} else if name == "padding" {
            strs := strings.Split(value, ",")
			view.Padding = CreatePadding(ConvertToFloat64(strs[0]), ConvertToFloat64(strs[1]), ConvertToFloat64(strs[2]), ConvertToFloat64(strs[3]))
		} else if name == "margin" {
            strs := strings.Split(value, ",")
			view.Margin = CreatePadding(ConvertToFloat64(strs[0]), ConvertToFloat64(strs[1]), ConvertToFloat64(strs[2]), ConvertToFloat64(strs[3]))
        } else if name == "hoveredcolor" {
            lowerStr := strings.ToLower(value)
			if strings.Contains(lowerStr, "rgb") {
				view.HoveredColor = value
			} else {
				view.HoveredColor = "none"
			}
		} else if name == "pushedcolor" {
            lowerStr := strings.ToLower(value)
			if strings.Contains(lowerStr, "rgb") {
				view.PushedColor = value
			} else {
				view.PushedColor = "none"
			}
		} else if name == "layout" {
            if view.ViewType == "tabview"{
			    view.GetTabView().Layout = value
            }
		} else if name == "width"{
            if strings.Contains(value, "%"){
                view.ExAttributes["widthstr"] = value
            }else{
                view.Size.Cx = ConvertToFloat64(value)
            }
        } else if name == "height"{
            if strings.Contains(value, "%"){
                view.ExAttributes["heightstr"] = value
            }else{
                view.Size.Cy = ConvertToFloat64(value)
            }
        } else if name == "left"{
            if strings.Contains(value, "%"){
                view.ExAttributes["leftstr"] = value
            }else{
                view.Location.X = ConvertToFloat64(value)
            }
        } else if name == "top"{
            if strings.Contains(value, "%"){
                view.ExAttributes["topstr"] = value
            }else{
                view.Location.Y = ConvertToFloat64(value)
            }
        }else{
            view.ExAttributes[name] = value
        }
    }
}

/*
* 读取Xml中的树节点
* tree 树
* parentNode 父节点
* xmlNode Xml节点
*/
func ReadTreeXmlNodeDefault(tree *FCView, parentNode *FCTreeNode, xmlNode *FCXmlNode) {
	treeNode := CreateTreeNode()
	treeNode.Value = xmlNode.Attributes["text"]
	AppendTreeNode(tree, treeNode, parentNode)
	for i := 0; i < len(xmlNode.Children); i++{
		child := xmlNode.Children[i]
		nodeName := strings.ToLower(child.NodeName)
		if nodeName == "node" {
			ReadTreeXmlNodeDefault(tree, treeNode, child)
		}
	}
}

/*
* 读取Xml
* paint 绘图对象
* node节点
* parent 父视图
*/
func ReadXmlNodeDefault(paint *FCPaint, node *FCXmlNode, parent *FCView) {
    for i := 0; i < len(node.Children); i++{
		child := node.Children[i]
		view := new(FCView)
        view.IsNotEmpty = false
        viewType := ""
		nodeName := strings.ToLower(child.NodeName)
		if nodeName == "div" || nodeName == "view" {
			viewType = child.Attributes["type"]
			if viewType == "splitlayout" {
				view = CreateView("split")
			}else if viewType == "layout" {
				view = CreateView("layout")
			}else if viewType == "tab" {
				view = CreateView("tabview")
			}else if viewType == "tabpage" {
				view = CreateView("tabpage")
			}else if viewType == "radio" {
				view = CreateView("radiobutton")
			}else if viewType == "text" || viewType == "range"|| viewType == "datetime"{
				view = CreateView("textbox")
			}else if viewType == "checkbox" {
				view = CreateView("checkbox")
			}else if viewType == "custom" {
                cid := child.Attributes["cid"]
				view = CreateView("div")
                view.ViewType = cid
			}else {
				view = CreateView("div")
			}
		}else if nodeName == "select" {
            view = CreateView("combobox")
        }else if nodeName == "input" {
			viewType = child.Attributes["type"]
			if viewType == "radio" {
				view = CreateView("radiobutton")
			}else if viewType == "text" || viewType == "range"|| viewType == "datetime" {
				view = CreateView("textbox")
			}else if viewType == "checkbox" {
				view = CreateView("checkbox")
			}else if viewType == "custom" {
                cid := child.Attributes["cid"]
				view = CreateView("button")
                view.ViewType = cid
			}else {
				view = CreateView("button")
			}
		}else if nodeName == "chart" {
			view = CreateView("chart")
		}else if nodeName == "calendar" {
			view = CreateView("calendar")
		}else if nodeName == "table" {
			view = CreateView("grid")
		} else if nodeName == "tree" {
			view = CreateView("tree")
		} else if nodeName == "label" {
			view = CreateView("label")
		}else {
			view = CreateView("custom")
		}
        view.SetPaint(paint)
        view.SetParent(parent)
		SetAttributeDefault(view, child)
		if view.IsNotEmpty {
			if viewType == "tabpage" {
				tabButton := CreateView("button")
				tabButton.ViewType = "tabbutton";
                atrHeaderSize,ok := child.Attributes["headersize"]
                if ok {
                    strs := strings.Split(atrHeaderSize, ",")
                    tabButton.Size = CreateSize(ConvertToFloat64(strs[0]), ConvertToFloat64(strs[1]))
                }else{
                    tabButton.Size = CreateSize(100, 20)
                }
				if view.GetPaint().DefaultUIStyle == "dark" {
					tabButton.BackColor = "rgb(0,0,0)"
					tabButton.BorderColor = "rgb(100,100,100)"
					tabButton.TextColor = "rgb(255,255,255)"
				} else if view.GetPaint().DefaultUIStyle == "light" {
					tabButton.BackColor = "rgb(255,255,255)"
					tabButton.BorderColor = "rgb(150,150,150)"
					tabButton.TextColor = "rgb(0,0,0)"
				}
				tabButton.Text = view.Text;
				AddTabPage(view.GetParent(), view, tabButton)
			} else {
				if parent.IsNotEmpty {
                    parent.Views = append(parent.Views, view)
				} else {
					paint.Views = append(paint.Views, view)
				}
			}
			if viewType == "splitlayout" {
                atrDatum,ok := child.Attributes["datumsize"]
                if ok {
                    strs := strings.Split(atrDatum, ",")
                    view.Size = CreateSize(ConvertToFloat64(strs[0]), ConvertToFloat64(strs[1]))
                }
				splitter := CreateView("button")
				if view.GetPaint().DefaultUIStyle == "dark" {
					splitter.BackColor = "rgb(100,100,100)"
				} else if view.GetPaint().DefaultUIStyle == "light" {
					splitter.BackColor = "rgb(150,150,150)"
				}
                canDragSplitter,ok2 := child.Attributes["candragsplitter"]
                if ok2 {
                    if canDragSplitter == "true"{
                        splitter.AllowDrag = true
                    }
                }
                AddViewToParent(splitter, view)
				view.GetSplitDiv().SetSplitter(splitter)
				splitterposition := child.Attributes["splitterposition"]
				splitStr := strings.Split(splitterposition, ",")
				if len(splitStr) >= 4 {
					splitRect := CreateRect(ConvertToFloat64(splitStr[0]), ConvertToFloat64(splitStr[1]), ConvertToFloat64(splitStr[2]), ConvertToFloat64(splitStr[3]))
					splitter.Location = CreatePoint(splitRect.Left, splitRect.Top)
					splitter.Size = CreateSize(splitRect.Right - splitRect.Left, splitRect.Bottom - splitRect.Top)
				} else {
					sSize := ConvertToFloat64(splitStr[1])
					sPosition := ConvertToFloat64(splitStr[0])
					if view.GetSplitDiv().LayoutStyle == "lefttoright" || view.GetSplitDiv().LayoutStyle == "righttoleft" {
						splitter.Location = CreatePoint(sPosition, 0)
						splitter.Size = CreateSize(sSize, view.Size.Cy)
					} else {
						splitter.Location = CreatePoint(0, sPosition)
						splitter.Size = CreateSize(view.Size.Cx, sSize)
					}
				}
				ReadXmlNodeDefault(paint, child, view)
				view.GetSplitDiv().SetFirstView(view.Views[1])
				view.GetSplitDiv().SetSecondView(view.Views[2])
				view.GetSplitDiv().OldSize = CreateSize(view.Size.Cx, view.Size.Cy)
				ResetSplitLayoutDiv(view)
			} else if viewType == "tab" {
				ReadXmlNodeDefault(paint, child, view)
                inTabView := view.GetTabView()
				if len(inTabView.TabPages) > 0 {
                    strSelectedIndex,ok := child.Attributes["selectedindex"]
                    if ok {
                        selectedIndex := ConvertToInt(strSelectedIndex)
                        if(selectedIndex >= 0 && selectedIndex < len(inTabView.TabPages)){
                            inTabView.TabPages[selectedIndex].Visible = true
                        }else{
                            inTabView.TabPages[len(inTabView.TabPages) - 1].Visible = true
                        }
                    }else{
					    inTabView.TabPages[len(inTabView.TabPages) - 1].Visible = true
                    }
				}
			} else if nodeName == "table" {
                for n := 0; n < len(child.Children); n++{
					tChild := child.Children[n];
					if tChild.NodeName == "tr" {
                        gridRow := CreateGridRow()
                        gridRow.IsNotEmpty = false
                        for j := 0; j < len(tChild.Children); j++{
							sunNodeName := strings.ToLower(tChild.Children[j].NodeName)
							if sunNodeName == "th" {
								gridColumn := CreateGridColumn()
                                if view.GetPaint().DefaultUIStyle == "light" {
									gridColumn.BackColor = "rgb(230,230,230)"
									gridColumn.BorderColor = "rgb(150,150,150)"
									gridColumn.TextColor = "rgb(0,0,0)"
								} else if view.GetPaint().DefaultUIStyle == "dark" {
									gridColumn.BackColor = "rgb(50,50,50)"
									gridColumn.BorderColor = "rgb(100,100,100)"
									gridColumn.TextColor = "rgb(255,255,255)"
								}
								gridColumn.Width = 100;
                                atrWidth,okW := tChild.Children[j].Attributes["width"]
                                if okW {
                                    if strings.Contains(atrWidth, "%"){
                                        gridColumn.WidthStr = atrWidth
                                    }else{
                                        gridColumn.Width = ConvertToFloat64(atrWidth)
                                    }
                                }
                                atrBackColor,okW2 := tChild.Children[j].Attributes["backcolor"]
                                if okW2 {
                                    gridColumn.BackColor = atrBackColor
                                }
                                atrTextColor,okW3 := tChild.Children[j].Attributes["textcolor"]
                                if okW3 {
                                    gridColumn.TextColor = atrTextColor
                                }
                                atrBorderColor,okW4 := tChild.Children[j].Attributes["bordercolor"]
                                if okW4 {
                                    gridColumn.BorderColor = atrBorderColor
                                }
                                atrFont,okW5 := tChild.Children[j].Attributes["font"]
                                if okW5 {
                                    gridColumn.Font = atrFont
                                }
								gridColumn.Text = tChild.Children[j].Attributes["text"]
								view.GetGrid().Columns = append(view.GetGrid().Columns, gridColumn)
							}else if sunNodeName == "td" {
                                if !gridRow.IsNotEmpty{
                                    gridRow = CreateGridRow()
                                    view.GetGrid().Rows = append(view.GetGrid().Rows, gridRow)
                                }
                                gridCell := CreateGridCell()
                                gridCell.Value = tChild.Children[j].Content
                                gridRow.Cells = append(gridRow.Cells, gridCell)
                            }
						}
					}
				}
			}else if nodeName == "tree" {
                treeColumn := CreateTreeColumn()
				view.GetTree().Columns = append(view.GetTree().Columns, treeColumn)
			    columnWidth := 0.0
                for n := 0; n < len(child.Children); n++{
					tChild := child.Children[n];
					if tChild.NodeName == "nodes" {
                        for j := 0; j < len(tChild.Children); j++{
							sunNodeName := strings.ToLower(tChild.Children[j].NodeName)
							if sunNodeName == "node" {
                                noneNode := CreateTreeNode()
                                noneNode.IsNotEmpty = false
                                ReadTreeXmlNodeDefault(view, noneNode, tChild.Children[j]);
                            }
                        }
                    }else if tChild.NodeName == "tr" {
                        for j := 0; j < len(tChild.Children); j++{
							sunNodeName := strings.ToLower(tChild.Children[j].NodeName)
							if sunNodeName == "th" {
                                atrWidth,okW := tChild.Children[j].Attributes["width"]
                                if okW {
                                    if strings.Contains(atrWidth, "%"){
                                        treeColumn.WidthStr = atrWidth
                                    }else{
                                       columnWidth += ConvertToFloat64(atrWidth)
                                    }
                                }
                            }
                        }
                    }
                }
                if columnWidth > 0 {
					treeColumn.Width = columnWidth
				}
            }else if view.ViewType == "textbox"{              
                view.ExView = true
				paint.GdiPlus.createView(view.ViewType, view.ViewName)
				if view.GetPaint().DefaultUIStyle == "dark"{
					paint.GdiPlus.setAttribute(view.ViewName, "backcolor", "rgb(0,0,0)")
					paint.GdiPlus.setAttribute(view.ViewName, "bordercolor", "rgb(100,100,100)")
					paint.GdiPlus.setAttribute(view.ViewName, "textcolor", "rgb(255,255,255)")
                }else if view.GetPaint().DefaultUIStyle == "light"{
					paint.GdiPlus.setAttribute(view.ViewName, "backcolor", "rgb(255,255,255)")
					paint.GdiPlus.setAttribute(view.ViewName, "bordercolor", "rgb(150,150,150)")
					paint.GdiPlus.setAttribute(view.ViewName, "textcolor", "rgb(0,0,0)")
                }
                for key,value := range child.Attributes{
                    name := strings.ToLower(key)
                    paint.GdiPlus.setAttribute(view.ViewName, name, value)
                }		
            }else if nodeName == "calendar"{
                InitCalendar(view)
                cYear := GetYear(view, 2022)
                cMonth := cYear.Months[10]
                cDay := cMonth.Days[1]
                view.GetCalendar().SetSelectedDay(cDay)
                UpdateCalendar(view)
			}else if nodeName == "select"{
                newMenu := CreateView("menu")
                view.GetComboBox().SetDropDownMenu(newMenu)
				newMenu.GetMenu().SetComboBox(view)
				AddView(newMenu, paint)
                newMenu.Size.Cx = view.Size.Cx
                for n := 0; n < len(child.Children); n++{
					tChild := child.Children[n];
					if tChild.NodeName == "option" {
                        menuItem := CreateView("menuitem")
						AddMenuItem(menuItem, newMenu)
                        SetAttributeDefault(menuItem, tChild)
                    }
                }
                if len(newMenu.GetMenu().Items) > 0 {
                    strSelectedIndex,ok := child.Attributes["selectedindex"]
                    if ok {
                        selectedIndex := ConvertToInt(strSelectedIndex)
                        if(selectedIndex >= 0 && selectedIndex < len(newMenu.GetMenu().Items)){
                            view.GetComboBox().SelectedIndex = selectedIndex
							view.Text = newMenu.GetMenu().Items[selectedIndex].Text
                        }else{
                            view.GetComboBox().SelectedIndex = 0
							view.Text = newMenu.GetMenu().Items[0].Text
                        }
                    }else{
                        view.GetComboBox().SelectedIndex = 0
						view.Text = newMenu.GetMenu().Items[0].Text
                    }
				}
            }else {
                if view.ViewType != "chart"{
				    ReadXmlNodeDefault(paint, child, view)
                }
			}
		}
	}
}

/*
* 加载图形界面
* paint:绘图对象
* xml:Xml内容
*/
func RenderFaceCat(paint *FCPaint, xmlStr string) {
    rect := GetClientRectW32(paint.HWnd)
	paint.Size = CreateSize(float64(rect.Right - rect.Left), float64(rect.Bottom - rect.Top))
    decoder := xml.NewDecoder(strings.NewReader(xmlStr))
    rootNode := new(FCXmlNode)
    rootNode.IsNotEmpty = false
    var xmlNodes []*FCXmlNode
    var isBody = false
    for t, err := decoder.Token(); err == nil; t, err = decoder.Token() {
        if err != nil{
            fmt.Println(err)
            break
        }
        switch token := t.(type) {
            case xml.StartElement:
                name := token.Name.Local
                if(isBody){
                    xmlNode := CreateXmlNode()
                    xmlNode.NodeName = name
                    for _, attr := range token.Attr {
                        atrName := attr.Name.Local
                        atrValue := attr.Value
                        xmlNode.Attributes[atrName] = atrValue
                    }
                    lastNode := xmlNodes[len(xmlNodes) - 1]
                    lastNode.Children = append(lastNode.Children, xmlNode)
                    xmlNodes = append(xmlNodes, xmlNode)
                }else{
                    if name == "body"{
                        isBody = true
                        xmlNode := CreateXmlNode()
                        xmlNode.NodeName = name
                        rootNode = xmlNode
                        xmlNodes = append(xmlNodes, xmlNode)
                    }
                }
            case xml.CharData:
                if len(xmlNodes) > 0{
                    xmlNodes[len(xmlNodes) - 1].Content = string([]byte(token))
                }
            case xml.EndElement:
                name := token.Name.Local
                if name == "body"{
                        isBody = false
                }else{
                    if isBody{
                        if len(xmlNodes) > 0{
                            index := len(xmlNodes) - 1
                            xmlNodes = append(xmlNodes[:index], xmlNodes[index + 1:]...)
                        }
                    }
                }
        }
    }  
    if rootNode.IsNotEmpty{
        noneView := new(FCView)
        noneView.IsNotEmpty = false
        ReadXmlNodeDefault(paint, rootNode, noneView)
    }
    if paint.OnUpdateView != nil{
        paint.OnUpdateView(paint.Views)
    }else{
        UpdateViewDefault(paint.Views)
    }
	Invalidate(paint)
}

var moduser32 = syscall.NewLazyDLL("user32.dll")
var procGetDC = moduser32.NewProc("GetDC")
var procReleaseDC = moduser32.NewProc("ReleaseDC")
var procPostQuitMessage = moduser32.NewProc("PostQuitMessage")
var procGetClientRect = moduser32.NewProc("GetClientRect")
var procGetCursorPos = moduser32.NewProc("GetCursorPos")
var procScreenToClient = moduser32.NewProc("ScreenToClient")
var procDefWindowProc = moduser32.NewProc("DefWindowProcW")
var procRegisterClassEx = moduser32.NewProc("RegisterClassExW")
var procCreateWindowEx = moduser32.NewProc("CreateWindowExW")
var procShowWindow = moduser32.NewProc("ShowWindow")
var procUpdateWindow = moduser32.NewProc("UpdateWindow")
var procGetMessage = moduser32.NewProc("GetMessageW")
var procTranslateAccelerator = moduser32.NewProc("TranslateAccelerator")
var procTranslateMessage = moduser32.NewProc("TranslateMessage")
var procSetTimer = moduser32.NewProc("SetTimer")
var procDispatchMessage = moduser32.NewProc("DispatchMessageW")
var procIsWindowVisible = moduser32.NewProc("IsWindowVisible")
var procMoveWindow = moduser32.NewProc("MoveWindow")
var procSendMessage = moduser32.NewProc("SendMessageW")
var procGetWindowLong = moduser32.NewProc("GetWindowLongW")
var procSetWindowLong = moduser32.NewProc("SetWindowLongW")
var procLoadCursor = moduser32.NewProc("LoadCursorW")
var modkernel32 = syscall.NewLazyDLL("kernel32.dll")
var procGetModuleHandle = modkernel32.NewProc("GetModuleHandleW")

const WM_CHAR = 258
const WM_KEYDOWN = 256
const WM_SYSKEYDOWN = 260
const WM_KEYUP = 257
const WM_SYSKEYUP = 261
const WM_PAINT = 15
const WM_MOUSEMOVE = 512
const WM_MOUSEWHEEL = 522
const WM_LBUTTONUP = 514
const WM_LBUTTONDBLCLK = 515
const WM_LBUTTONDOWN = 513
const WM_RBUTTONDOWN = 516
const WM_RBUTTONUP = 517
const WM_RBUTTONDBLCLK = 518
const WM_SIZE = 5
const WM_ERASEBKGND = 20
const WM_DESTROY = 2
const COLOR_WINDOW = 5
const CS_HREDRAW = 0x00000002
const CS_VREDRAW = 0x00000001
const CS_DBLCLKS = 0x00000008
const CW_USEDEFAULT = ^0x7fffffff
const WS_VISIBLE = 0X10000000
const WS_CHILD = 0X40000000
const WS_BORDER = 0X00800000
const SW_SHOW = 5
const SW_HIDE = 0
const IDI_APPLICATION = 32512
const SW_SHOWMAXIMIZED = 3
const WS_OVERLAPPEDWINDOW = 0X00000000 | 0X00C00000 | 0X00080000 | 0X00040000 | 0X00020000 | 0X00010000
const WS_CLIPCHILDREN = 0X02000000
const WM_TIMER = 275
const GWL_EXSTYLE = -20
const ES_CENTER = 0x0001
type HINSTANCE uintptr
type HDC uintptr
type HWND uintptr
type HICON uintptr
type HCURSOR uintptr
type HBRUSH uintptr
type ATOM uint16
type HMENU uintptr
type BOOL int32

type POINT struct {
	X, Y int32
}

type RECT struct {
	Left, Top, Right, Bottom int32
}

func BoolToBOOL(value bool) BOOL {
	if value {
		return 1
	}
	return 0
}

func GetDCW32(hwnd HWND) HDC {
	ret, _, _ := procGetDC.Call(
		uintptr(hwnd))

	return HDC(ret)
}

func ReleaseDCW32(hwnd HWND, hDC HDC) bool {
	ret, _, _ := procReleaseDC.Call(
		uintptr(hwnd),
		uintptr(hDC))

	return ret != 0
}

func PostQuitMessageW32(exitCode int) {
	procPostQuitMessage.Call(
		uintptr(exitCode))
}

func GetClientRectW32(hwnd HWND) *RECT {
	rect := RECT{}
	procGetClientRect.Call(
		uintptr(hwnd),
		uintptr(unsafe.Pointer(&rect)))
	return &rect
}

func GetCursorPosW32() (x, y int, ok bool) {
	pt := POINT{}
	ret, _, _ := procGetCursorPos.Call(uintptr(unsafe.Pointer(&pt)))
	return int(pt.X), int(pt.Y), ret != 0
}

func ScreenToClientW32(hwnd HWND, x, y int) (X, Y int, ok bool) {
	pt := POINT{X: int32(x), Y: int32(y)}
	ret, _, _ := procScreenToClient.Call(
		uintptr(hwnd),
		uintptr(unsafe.Pointer(&pt)))

	return int(pt.X), int(pt.Y), ret != 0
}

func DefWindowProcW32(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
	ret, _, _ := procDefWindowProc.Call(
		uintptr(hwnd),
		uintptr(msg),
		wParam,
		lParam)

	return ret
}

func GetModuleHandleW32(modulename string) HINSTANCE {
	var mn uintptr
	if modulename == "" {
		mn = 0
	} else {
		mn = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(modulename)))
	}
	ret, _, _ := procGetModuleHandle.Call(mn)
	return HINSTANCE(ret)
}

func RegisterClassExW32(wndClassEx *WNDCLASSEX) ATOM {
	ret, _, _ := procRegisterClassEx.Call(uintptr(unsafe.Pointer(wndClassEx)))
	return ATOM(ret)
}

func CreateWindowExW32(exStyle uint, className, windowName *uint16,
	style uint, x, y, width, height int, parent HWND, menu HMENU,
	instance HINSTANCE, param unsafe.Pointer) HWND {
	ret, _, _ := procCreateWindowEx.Call(
		uintptr(exStyle),
		uintptr(unsafe.Pointer(className)),
		uintptr(unsafe.Pointer(windowName)),
		uintptr(style),
		uintptr(x),
		uintptr(y),
		uintptr(width),
		uintptr(height),
		uintptr(parent),
		uintptr(menu),
		uintptr(instance),
		uintptr(param))

	return HWND(ret)
}

func ShowWindowW32(hwnd HWND, cmdshow int) bool {
	ret, _, _ := procShowWindow.Call(
		uintptr(hwnd),
		uintptr(cmdshow))

	return ret != 0
}

func UpdateWindowW32(hwnd HWND) bool {
	ret, _, _ := procUpdateWindow.Call(
		uintptr(hwnd))
	return ret != 0
}

func GetMessageW32(msg *MSG, hwnd HWND, msgFilterMin, msgFilterMax uint32) int {
	ret, _, _ := procGetMessage.Call(
		uintptr(unsafe.Pointer(msg)),
		uintptr(hwnd),
		uintptr(msgFilterMin),
		uintptr(msgFilterMax))

	return int(ret)
}

func TranslateAccelerator32(hwnd HWND, msg *MSG) bool {
	ret, _, _ := procTranslateAccelerator.Call(
        uintptr(hwnd),
        uintptr(0),
		uintptr(unsafe.Pointer(msg)))
    return ret != 0
}

func TranslateMessageW32(msg *MSG) bool {
	ret, _, _ := procTranslateMessage.Call(
		uintptr(unsafe.Pointer(msg)))

	return ret != 0
}

func DispatchMessageW32(msg *MSG) uintptr {
	ret, _, _ := procDispatchMessage.Call(
		uintptr(unsafe.Pointer(msg)))
	return ret
}

func SetTimerW32(hwnd HWND, nIDEvent uint32, uElapse uint32, lpTimerProc uintptr) uintptr {
	ret, _, _ := procSetTimer.Call(
		uintptr(hwnd),
		uintptr(nIDEvent),
		uintptr(uElapse),
		lpTimerProc,
	)
	return ret
}

func IsWindowVisibleW32(hwnd HWND) bool {
	ret, _, _ := procIsWindowVisible.Call(
		uintptr(hwnd))

	return ret != 0
}

func MoveWindowW32(hwnd HWND, x, y, width, height int, repaint bool) bool {
	ret, _, _ := procMoveWindow.Call(
		uintptr(hwnd),
		uintptr(x),
		uintptr(y),
		uintptr(width),
		uintptr(height),
		uintptr(BoolToBOOL(repaint)))
	return ret != 0
}

func SendMessageW32(hwnd HWND, msg uint32, wParam, lParam uintptr) uintptr {
	ret, _, _ := procSendMessage.Call(
		uintptr(hwnd),
		uintptr(msg),
		wParam,
		lParam)

	return ret
}

func GetWindowLongW32(hwnd HWND, index int) int32 {
	ret, _, _ := procGetWindowLong.Call(
		uintptr(hwnd),
		uintptr(index))

	return int32(ret)
}

func SetWindowLongW32(hwnd HWND, index int, value uint32) uint32 {
	ret, _, _ := procSetWindowLong.Call(
		uintptr(hwnd),
		uintptr(index),
		uintptr(value))

	return uint32(ret)
}

func LoadCursorW32(instance HINSTANCE, cursorName *uint16) HCURSOR {
	ret, _, _ := procLoadCursor.Call(
		uintptr(instance),
		uintptr(unsafe.Pointer(cursorName)))

	return HCURSOR(ret)

}

type WNDCLASSEX struct {
	Size       uint32
	Style      uint32
	WndProc    uintptr
	ClsExtra   int32
	WndExtra   int32
	Instance   HINSTANCE
	Icon       HICON
	Cursor     HCURSOR
	Background HBRUSH
	MenuName   *uint16
	ClassName  *uint16
	IconSm     HICON
}

type MSG struct {
	Hwnd    HWND
	Message uint32
	WParam  uintptr
	LParam  uintptr
	Time    uint32
	Pt      POINT
}

var mainWindowHandle = HWND(0) //主窗体句柄
var showWindowState = 0 //显示的窗体状态
var showWindowSize = CreateSize(0, 0) //显示的窗体大小
var showWindowLocation = CreatePoint(0, 0) //显示的窗体大小

/*
* 创建默认的窗体
*/
func CreateMainWindow(paint *FCPaint, title string, callBack WndProcCallBack){
    var wc WNDCLASSEX
    wc.Size = uint32(unsafe.Sizeof(wc))
    wc.WndProc = syscall.NewCallback(callBack)
    wc.Cursor = LoadCursorW32(0, (*uint16)(unsafe.Pointer(uintptr(IDI_APPLICATION))))
    wc.Background = COLOR_WINDOW + 1

    b := make([]byte, 16)
    _, err := rand.Read(b)
    if err != nil {
    }
    uuid := fmt.Sprintf("%x-%x-%x-%x-%x",
        b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
    wc.ClassName = syscall.StringToUTF16Ptr(uuid)
    wc.Style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS
    RegisterClassExW32(&wc)
    hWnd := HWND(0)
    if showWindowSize.Cx > 0 && showWindowSize.Cy > 0{
            hWnd = CreateWindowExW32(
            0,
            syscall.StringToUTF16Ptr(uuid),
            syscall.StringToUTF16Ptr(title),
            WS_OVERLAPPEDWINDOW,
            int(showWindowLocation.X),
            int(showWindowLocation.Y),
            int(showWindowSize.Cx),
            int(showWindowSize.Cy),
            0,
            0,
            0,
            nil)
    }else{
        hWnd = CreateWindowExW32(
            0,
            syscall.StringToUTF16Ptr(uuid),
            syscall.StringToUTF16Ptr(title),
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0,
            0,
            0,
            nil)
    }
    paint.HWnd = hWnd
    mainWindowHandle = hWnd
    paint.GdiPlus.createGdiPlus(hWnd)
    showWindowSize = CreateSize(0, 0)
}

/*
* 创建默认的窗体
*/
func CreateWindow(paint *FCPaint, title string, callBack WndProcCallBack){
    var wc WNDCLASSEX
    wc.Size = uint32(unsafe.Sizeof(wc))
    wc.WndProc = syscall.NewCallback(callBack)
    wc.Cursor = LoadCursorW32(0, (*uint16)(unsafe.Pointer(uintptr(IDI_APPLICATION))))
    wc.Background = COLOR_WINDOW + 1
    b := make([]byte, 16)
    _, err := rand.Read(b)
    if err != nil {
    }
    uuid := fmt.Sprintf("%x-%x-%x-%x-%x",
        b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
    wc.ClassName = syscall.StringToUTF16Ptr(uuid)
    wc.Style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS
    RegisterClassExW32(&wc)
    hWnd := HWND(0)
    if showWindowSize.Cx > 0 && showWindowSize.Cy > 0{
            hWnd = CreateWindowExW32(
            0,
            syscall.StringToUTF16Ptr(uuid),
            syscall.StringToUTF16Ptr(title),
            WS_OVERLAPPEDWINDOW,
            int(showWindowLocation.X),
            int(showWindowLocation.Y),
            int(showWindowSize.Cx),
            int(showWindowSize.Cy),
            0,
            0,
            0,
            nil)
    }else{
        hWnd = CreateWindowExW32(
            0,
            syscall.StringToUTF16Ptr(uuid),
            syscall.StringToUTF16Ptr(title),
            WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            CW_USEDEFAULT,
            0,
            0,
            0,
            nil)
    }
    paint.HWnd = hWnd
    paint.GdiPlus.createGdiPlus(hWnd)
    showWindowSize = CreateSize(0, 0)
}

/*
* 显示窗体
*/
func ShowWindow(paint *FCPaint){
    if(showWindowState == 1){
        ShowWindowW32(paint.HWnd, SW_SHOWMAXIMIZED)
    }else{
        ShowWindowW32(paint.HWnd, SW_SHOW)
    }
    UpdateWindowW32(paint.HWnd)
    showWindowState = 0
    if paint.HWnd == mainWindowHandle{
        paint.GdiPlus.pumpMessage()
    }
}

/*
* 设置显示最大化
*/
func SetMaxWindow(){
    showWindowState = 1
}

/*
* 隐藏窗体
*/
func HideWindow(paint *FCPaint){
    showWindowState = 0
    ShowWindowW32(paint.HWnd, SW_HIDE)
}

/*
*设置要创建的窗体大小
*/
func SetWindowRect(location FCPoint, size FCSize){
    showWindowLocation = location
    showWindowSize = size
}